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.NonNull;
23 import android.annotation.Nullable;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.view.InputEvent;
27 
28 import com.android.adservices.AdServicesParcelableUtil;
29 import com.android.internal.util.Preconditions;
30 
31 import java.util.Objects;
32 
33 /**
34  * Input object wrapping the required arguments needed to report an interaction.
35  *
36  * @hide
37  */
38 public final class ReportInteractionInput implements Parcelable {
39 
40     private static final int UNSET_REPORTING_DESTINATIONS = 0;
41     private static final String UNSET_REPORTING_DESTINATIONS_MESSAGE =
42             "Reporting Destinations bitfield not set.";
43 
44     private final long mAdSelectionId;
45     @NonNull private final String mInteractionKey;
46     @NonNull private final String mInteractionData;
47     @NonNull private final String mCallerPackageName;
48     private final int mReportingDestinations; // buyer, seller, or both
49     @Nullable private final InputEvent mInputEvent;
50     @Nullable private final String mAdId;
51     @Nullable private final String mCallerSdkName;
52 
53     @NonNull
54     public static final Creator<ReportInteractionInput> CREATOR =
55             new Creator<ReportInteractionInput>() {
56                 @Override
57                 public ReportInteractionInput createFromParcel(@NonNull Parcel in) {
58                     Objects.requireNonNull(in);
59 
60                     return new ReportInteractionInput(in);
61                 }
62 
63                 @Override
64                 public ReportInteractionInput[] newArray(int size) {
65                     return new ReportInteractionInput[size];
66                 }
67             };
68 
ReportInteractionInput( long adSelectionId, @NonNull String interactionKey, @NonNull String interactionData, @NonNull String callerPackageName, int reportingDestinations, @Nullable InputEvent inputEvent, @Nullable String adId, @Nullable String callerSdkName)69     private ReportInteractionInput(
70             long adSelectionId,
71             @NonNull String interactionKey,
72             @NonNull String interactionData,
73             @NonNull String callerPackageName,
74             int reportingDestinations,
75             @Nullable InputEvent inputEvent,
76             @Nullable String adId,
77             @Nullable String callerSdkName) {
78         Objects.requireNonNull(interactionKey);
79         Objects.requireNonNull(interactionData);
80         Objects.requireNonNull(callerPackageName);
81 
82         this.mAdSelectionId = adSelectionId;
83         this.mInteractionKey = interactionKey;
84         this.mInteractionData = interactionData;
85         this.mCallerPackageName = callerPackageName;
86         this.mReportingDestinations = reportingDestinations;
87         this.mInputEvent = inputEvent;
88         this.mAdId = adId;
89         this.mCallerSdkName = callerSdkName;
90     }
91 
ReportInteractionInput(@onNull Parcel in)92     private ReportInteractionInput(@NonNull Parcel in) {
93         this.mAdSelectionId = in.readLong();
94         this.mInteractionKey = in.readString();
95         this.mInteractionData = in.readString();
96         this.mCallerPackageName = in.readString();
97         this.mReportingDestinations = in.readInt();
98         this.mInputEvent =
99                 AdServicesParcelableUtil.readNullableFromParcel(
100                         in, InputEvent.CREATOR::createFromParcel);
101         this.mAdId =
102                 AdServicesParcelableUtil.readNullableFromParcel(
103                         in, (sourceParcel -> in.readString()));
104         this.mCallerSdkName =
105                 AdServicesParcelableUtil.readNullableFromParcel(
106                         in, (sourceParcel -> in.readString()));
107     }
108 
109     @Override
describeContents()110     public int describeContents() {
111         return 0;
112     }
113 
114     @Override
writeToParcel(@onNull Parcel dest, int flags)115     public void writeToParcel(@NonNull Parcel dest, int flags) {
116         Objects.requireNonNull(dest);
117         dest.writeLong(mAdSelectionId);
118         dest.writeString(mInteractionKey);
119         dest.writeString(mInteractionData);
120         dest.writeString(mCallerPackageName);
121         dest.writeInt(mReportingDestinations);
122         AdServicesParcelableUtil.writeNullableToParcel(
123                 dest,
124                 mInputEvent,
125                 (targetParcel, sourceInputEvent) ->
126                         sourceInputEvent.writeToParcel(targetParcel, flags));
127         AdServicesParcelableUtil.writeNullableToParcel(dest, mAdId, Parcel::writeString);
128         AdServicesParcelableUtil.writeNullableToParcel(dest, mCallerSdkName, Parcel::writeString);
129     }
130 
131     /** Returns the adSelectionId, the primary identifier of an ad selection process. */
getAdSelectionId()132     public long getAdSelectionId() {
133         return mAdSelectionId;
134     }
135 
136     /**
137      * Returns the interaction key, the type of interaction to be reported.
138      *
139      * <p>This will be used to fetch the {@code interactionReportingUri} associated with the {@code
140      * interactionKey} registered in {@code registerAdBeacon} after ad selection.
141      */
142     @NonNull
getInteractionKey()143     public String getInteractionKey() {
144         return mInteractionKey;
145     }
146 
147     /**
148      * Returns the interaction data.
149      *
150      * <p>After ad selection, this data is generated by the caller, and will be attached in a POST
151      * request to the {@code interactionReportingUri} registered in {@code registerAdBeacon}.
152      */
153     @NonNull
getInteractionData()154     public String getInteractionData() {
155         return mInteractionData;
156     }
157 
158     /** Returns the caller package name */
159     @NonNull
getCallerPackageName()160     public String getCallerPackageName() {
161         return mCallerPackageName;
162     }
163 
164     /** Returns the bitfield of reporting destinations to report to (buyer, seller, or both) */
getReportingDestinations()165     public int getReportingDestinations() {
166         return mReportingDestinations;
167     }
168 
169     /**
170      * Returns the input event associated with the user interaction.
171      *
172      * <p>This field is either {@code null}, representing a <em>view</em> event, or has an {@link
173      * InputEvent} object, representing a <em>click</em> event.
174      */
175     @Nullable
getInputEvent()176     public InputEvent getInputEvent() {
177         return mInputEvent;
178     }
179 
180     /**
181      * Returns the {@code AdId} to enable event-level debug reporting.
182      *
183      * <p>This field is either set and non-{@code null}, representing a valid and enabled {@code
184      * AdId} or {@code null}, representing an invalid or disabled {@code AdId}.
185      */
186     @Nullable
getAdId()187     public String getAdId() {
188         return mAdId;
189     }
190 
191     /** Returns the caller's sdk name. */
192     @Nullable
getCallerSdkName()193     public String getCallerSdkName() {
194         return mCallerSdkName;
195     }
196 
197     /**
198      * Builder for {@link ReportInteractionInput} objects.
199      *
200      * @hide
201      */
202     public static final class Builder {
203         private long mAdSelectionId = UNSET_AD_SELECTION_ID;
204         @Nullable private String mInteractionKey;
205         @Nullable private String mInteractionData;
206         @Nullable private String mCallerPackageName;
207         @Nullable private String mCallerSdkName;
208         private int mReportingDestinations = UNSET_REPORTING_DESTINATIONS;
209         @Nullable private InputEvent mInputEvent;
210         @Nullable private String mAdId;
211 
Builder()212         public Builder() {}
213 
214         /** Sets the adSelectionId. */
215         @NonNull
setAdSelectionId(long adSelectionId)216         public ReportInteractionInput.Builder setAdSelectionId(long adSelectionId) {
217             mAdSelectionId = adSelectionId;
218             return this;
219         }
220 
221         /** Sets the interactionKey. */
222         @NonNull
setInteractionKey(@onNull String interactionKey)223         public ReportInteractionInput.Builder setInteractionKey(@NonNull String interactionKey) {
224             Objects.requireNonNull(interactionKey);
225 
226             mInteractionKey = interactionKey;
227             return this;
228         }
229 
230         /** Sets the interactionData. */
231         @NonNull
setInteractionData(@onNull String interactionData)232         public ReportInteractionInput.Builder setInteractionData(@NonNull String interactionData) {
233             Objects.requireNonNull(interactionData);
234 
235             mInteractionData = interactionData;
236             return this;
237         }
238 
239         /** Sets the caller's package name. */
240         @NonNull
setCallerPackageName( @onNull String callerPackageName)241         public ReportInteractionInput.Builder setCallerPackageName(
242                 @NonNull String callerPackageName) {
243             Objects.requireNonNull(callerPackageName);
244 
245             mCallerPackageName = callerPackageName;
246             return this;
247         }
248 
249         /** Sets the bitfield of reporting destinations. */
250         @NonNull
setReportingDestinations(int reportingDestinations)251         public ReportInteractionInput.Builder setReportingDestinations(int reportingDestinations) {
252             Preconditions.checkArgument(
253                     reportingDestinations != UNSET_REPORTING_DESTINATIONS,
254                     UNSET_REPORTING_DESTINATIONS_MESSAGE);
255 
256             mReportingDestinations = reportingDestinations;
257             return this;
258         }
259 
260         /** Sets the input event associated with the user interaction. */
261         @NonNull
setInputEvent(@ullable InputEvent inputEvent)262         public ReportInteractionInput.Builder setInputEvent(@Nullable InputEvent inputEvent) {
263             mInputEvent = inputEvent;
264             return this;
265         }
266 
267         /** Sets the {@code AdId}. */
268         @NonNull
setAdId(@ullable String adId)269         public ReportInteractionInput.Builder setAdId(@Nullable String adId) {
270             mAdId = adId;
271             return this;
272         }
273 
274         /** Sets the caller's sdk name. */
275         @NonNull
setCallerSdkName(@ullable String callerSdkName)276         public ReportInteractionInput.Builder setCallerSdkName(@Nullable String callerSdkName) {
277             mCallerSdkName = callerSdkName;
278             return this;
279         }
280 
281         /** Builds a {@link ReportInteractionInput} instance. */
282         @NonNull
build()283         public ReportInteractionInput build() {
284             Objects.requireNonNull(mInteractionKey);
285             Objects.requireNonNull(mInteractionData);
286             Objects.requireNonNull(mCallerPackageName);
287 
288             Preconditions.checkArgument(
289                     mAdSelectionId != UNSET_AD_SELECTION_ID, UNSET_AD_SELECTION_ID_MESSAGE);
290             Preconditions.checkArgument(
291                     mReportingDestinations != UNSET_REPORTING_DESTINATIONS,
292                     UNSET_REPORTING_DESTINATIONS_MESSAGE);
293 
294             return new ReportInteractionInput(
295                     mAdSelectionId,
296                     mInteractionKey,
297                     mInteractionData,
298                     mCallerPackageName,
299                     mReportingDestinations,
300                     mInputEvent,
301                     mAdId,
302                     mCallerSdkName);
303         }
304     }
305 }
306