1 /*
2  * Copyright 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 androidx.privacysandbox.ads.adservices.adselection
18 
19 import android.annotation.SuppressLint
20 import android.os.Build
21 import android.os.ext.SdkExtensions
22 import android.util.Log
23 import android.view.InputEvent
24 import androidx.annotation.IntDef
25 import androidx.annotation.RequiresExtension
26 import androidx.annotation.RestrictTo
27 import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
28 import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
29 
30 /**
31  * Represent input parameters to the reportImpression API.
32  *
33  * @param adSelectionId An ID unique only to a device user that identifies a successful ad
34  *   selection.
35  * @param eventKey An event key, the type of ad event to be reported.
36  * @param eventData The ad event data
37  * @param reportingDestinations The bitfield of reporting destinations to report to (buyer, seller,
38  *   or both).
39  * @param inputEvent The input event associated with the user interaction.
40  */
41 @OptIn(ExperimentalFeatures.Ext10OptIn::class)
42 @ExperimentalFeatures.Ext8OptIn
43 class ReportEventRequest
44 @JvmOverloads
45 public constructor(
46     val adSelectionId: Long,
47     val eventKey: String,
48     val eventData: String,
49     @ReportingDestination val reportingDestinations: Int,
50     @property:ExperimentalFeatures.Ext10OptIn val inputEvent: InputEvent? = null
51 ) {
52     init {
53         require(
54             0 < reportingDestinations &&
55                 reportingDestinations <=
56                     (FLAG_REPORTING_DESTINATION_SELLER or FLAG_REPORTING_DESTINATION_BUYER)
<lambda>null57         ) {
58             "Invalid reporting destinations bitfield."
59         }
60     }
61 
62     /** Checks whether two [ReportImpressionRequest] objects contain the same information. */
equalsnull63     override fun equals(other: Any?): Boolean {
64         if (this === other) return true
65         if (other !is ReportEventRequest) return false
66         return this.adSelectionId == other.adSelectionId &&
67             this.eventKey == other.eventKey &&
68             this.eventData == other.eventData &&
69             this.reportingDestinations == other.reportingDestinations &&
70             this.inputEvent == other.inputEvent
71     }
72 
73     /** Returns the hash of the [ReportImpressionRequest] object's data. */
hashCodenull74     override fun hashCode(): Int {
75         var hash = adSelectionId.hashCode()
76         hash = 31 * hash + eventKey.hashCode()
77         hash = 31 * hash + eventData.hashCode()
78         hash = 31 * hash + reportingDestinations.hashCode()
79         hash = 31 * hash + inputEvent.hashCode()
80         return hash
81     }
82 
83     /** Overrides the toString method. */
toStringnull84     override fun toString(): String {
85         return "ReportEventRequest: adSelectionId=$adSelectionId, eventKey=$eventKey, " +
86             "eventData=$eventData, reportingDestinations=$reportingDestinations" +
87             "inputEvent=$inputEvent"
88     }
89 
90     @RestrictTo(RestrictTo.Scope.LIBRARY)
91     @Retention(AnnotationRetention.SOURCE)
92     @IntDef(
93         flag = true,
94         value =
95             [
96                 Companion.FLAG_REPORTING_DESTINATION_SELLER,
97                 Companion.FLAG_REPORTING_DESTINATION_BUYER
98             ]
99     )
100     annotation class ReportingDestination
101 
102     companion object {
103         const val FLAG_REPORTING_DESTINATION_SELLER: Int =
104             android.adservices.adselection.ReportEventRequest.FLAG_REPORTING_DESTINATION_SELLER
105         const val FLAG_REPORTING_DESTINATION_BUYER: Int =
106             android.adservices.adselection.ReportEventRequest.FLAG_REPORTING_DESTINATION_BUYER
107     }
108 
109     @SuppressLint("NewApi")
110     @RestrictTo(RestrictTo.Scope.LIBRARY)
111     @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 8)
112     @RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
convertToAdServicesnull113     internal fun convertToAdServices(): android.adservices.adselection.ReportEventRequest {
114         if (
115             AdServicesInfo.adServicesVersion() >= 10 || AdServicesInfo.extServicesVersionS() >= 10
116         ) {
117             return Ext10Impl.convertReportEventRequest(this)
118         }
119         return Ext8Impl.convertReportEventRequest(this)
120     }
121 
122     @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 10)
123     @RequiresExtension(extension = Build.VERSION_CODES.S, version = 10)
124     private class Ext10Impl private constructor() {
125         companion object {
convertReportEventRequestnull126             fun convertReportEventRequest(
127                 request: ReportEventRequest
128             ): android.adservices.adselection.ReportEventRequest {
129                 return android.adservices.adselection.ReportEventRequest.Builder(
130                         request.adSelectionId,
131                         request.eventKey,
132                         request.eventData,
133                         request.reportingDestinations
134                     )
135                     .setInputEvent(request.inputEvent)
136                     .build()
137             }
138         }
139     }
140 
141     @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 8)
142     @RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
143     private class Ext8Impl private constructor() {
144         companion object {
convertReportEventRequestnull145             fun convertReportEventRequest(
146                 request: ReportEventRequest
147             ): android.adservices.adselection.ReportEventRequest {
148                 request.inputEvent?.let {
149                     Log.w(
150                         "ReportEventRequest",
151                         "inputEvent is ignored. Min version to use inputEvent is API 31 ext 10"
152                     )
153                 }
154                 return android.adservices.adselection.ReportEventRequest.Builder(
155                         request.adSelectionId,
156                         request.eventKey,
157                         request.eventData,
158                         request.reportingDestinations
159                     )
160                     .build()
161             }
162         }
163     }
164 }
165