1 /*
2  * Copyright 2022 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.java.measurement
18 
19 import android.adservices.common.AdServicesPermissions
20 import android.content.Context
21 import android.net.Uri
22 import android.view.InputEvent
23 import androidx.annotation.DoNotInline
24 import androidx.annotation.RequiresPermission
25 import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
26 import androidx.privacysandbox.ads.adservices.java.internal.asListenableFuture
27 import androidx.privacysandbox.ads.adservices.measurement.DeletionRequest
28 import androidx.privacysandbox.ads.adservices.measurement.MeasurementManager
29 import androidx.privacysandbox.ads.adservices.measurement.MeasurementManager.Companion.obtain
30 import androidx.privacysandbox.ads.adservices.measurement.SourceRegistrationRequest
31 import androidx.privacysandbox.ads.adservices.measurement.WebSourceRegistrationRequest
32 import androidx.privacysandbox.ads.adservices.measurement.WebTriggerRegistrationRequest
33 import com.google.common.util.concurrent.ListenableFuture
34 import kotlinx.coroutines.CoroutineScope
35 import kotlinx.coroutines.Dispatchers
36 import kotlinx.coroutines.async
37 
38 /**
39  * This provides APIs for App and Ad-Sdks to access Privacy Sandbox Measurement APIs in a privacy
40  * preserving way. This class can be used by Java clients.
41  */
42 abstract class MeasurementManagerFutures internal constructor() {
43     /**
44      * Delete previous registrations.
45      *
46      * @param deletionRequest The request for deleting data.
47      * @return ListenableFuture. If the deletion is successful, result is null.
48      */
49     @SuppressWarnings("MissingNullability")
deleteRegistrationsAsyncnull50     abstract fun deleteRegistrationsAsync(deletionRequest: DeletionRequest): ListenableFuture<Unit>
51 
52     /**
53      * Register an attribution source (click or view).
54      *
55      * @param attributionSource the platform issues a request to this URI in order to fetch metadata
56      *   associated with the attribution source.
57      * @param inputEvent either an [InputEvent] object (for a click event) or null (for a view
58      *   event).
59      */
60     @SuppressWarnings("MissingNullability")
61     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
62     abstract fun registerSourceAsync(
63         attributionSource: Uri,
64         inputEvent: InputEvent?
65     ): ListenableFuture<Unit>
66 
67     /**
68      * Register a trigger (conversion).
69      *
70      * @param trigger the API issues a request to this URI to fetch metadata associated with the
71      *   trigger.
72      */
73     @SuppressWarnings("MissingNullability")
74     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
75     abstract fun registerTriggerAsync(trigger: Uri): ListenableFuture<Unit>
76 
77     /**
78      * Register attribution sources(click or view). This API will not process any redirects, all
79      * registration URLs should be supplied with the request.
80      *
81      * @param request source registration request
82      */
83     @ExperimentalFeatures.RegisterSourceOptIn
84     @SuppressWarnings("MissingNullability")
85     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
86     abstract fun registerSourceAsync(request: SourceRegistrationRequest): ListenableFuture<Unit>
87 
88     /**
89      * Register an attribution source(click or view) from web context. This API will not process any
90      * redirects, all registration URLs should be supplied with the request. At least one of
91      * appDestination or webDestination parameters are required to be provided.
92      *
93      * @param request source registration request
94      */
95     @SuppressWarnings("MissingNullability")
96     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
97     abstract fun registerWebSourceAsync(
98         request: WebSourceRegistrationRequest
99     ): ListenableFuture<Unit>
100 
101     /**
102      * Register an attribution trigger(click or view) from web context. This API will not process
103      * any redirects, all registration URLs should be supplied with the request.
104      * OutcomeReceiver#onError}.
105      *
106      * @param request trigger registration request
107      */
108     @SuppressWarnings("MissingNullability")
109     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
110     abstract fun registerWebTriggerAsync(
111         request: WebTriggerRegistrationRequest,
112     ): ListenableFuture<Unit>
113 
114     /**
115      * Get Measurement API status.
116      *
117      * The call returns an integer value (see [MeasurementManager.MEASUREMENT_API_STATE_DISABLED]
118      * and [MeasurementManager.MEASUREMENT_API_STATE_ENABLED] for possible values).
119      */
120     @SuppressWarnings("MissingNullability")
121     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
122     abstract fun getMeasurementApiStatusAsync(): ListenableFuture<Int>
123 
124     private class Api33Ext5JavaImpl(private val mMeasurementManager: MeasurementManager) :
125         MeasurementManagerFutures() {
126         @DoNotInline
127         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
128         override fun deleteRegistrationsAsync(
129             deletionRequest: DeletionRequest
130         ): ListenableFuture<Unit> {
131             return CoroutineScope(Dispatchers.Default)
132                 .async { mMeasurementManager.deleteRegistrations(deletionRequest) }
133                 .asListenableFuture()
134         }
135 
136         @DoNotInline
137         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
138         override fun registerSourceAsync(
139             attributionSource: Uri,
140             inputEvent: InputEvent?
141         ): ListenableFuture<Unit> {
142             return CoroutineScope(Dispatchers.Default)
143                 .async { mMeasurementManager.registerSource(attributionSource, inputEvent) }
144                 .asListenableFuture()
145         }
146 
147         @DoNotInline
148         @ExperimentalFeatures.RegisterSourceOptIn
149         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
150         override fun registerSourceAsync(
151             request: SourceRegistrationRequest
152         ): ListenableFuture<Unit> {
153             return CoroutineScope(Dispatchers.Default)
154                 .async { mMeasurementManager.registerSource(request) }
155                 .asListenableFuture()
156         }
157 
158         @DoNotInline
159         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
160         override fun registerTriggerAsync(trigger: Uri): ListenableFuture<Unit> {
161             return CoroutineScope(Dispatchers.Default)
162                 .async { mMeasurementManager.registerTrigger(trigger) }
163                 .asListenableFuture()
164         }
165 
166         @DoNotInline
167         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
168         override fun registerWebSourceAsync(
169             request: WebSourceRegistrationRequest
170         ): ListenableFuture<Unit> {
171             return CoroutineScope(Dispatchers.Default)
172                 .async { mMeasurementManager.registerWebSource(request) }
173                 .asListenableFuture()
174         }
175 
176         @DoNotInline
177         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
178         override fun registerWebTriggerAsync(
179             request: WebTriggerRegistrationRequest,
180         ): ListenableFuture<Unit> {
181             return CoroutineScope(Dispatchers.Default)
182                 .async { mMeasurementManager.registerWebTrigger(request) }
183                 .asListenableFuture()
184         }
185 
186         @DoNotInline
187         @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
188         override fun getMeasurementApiStatusAsync(): ListenableFuture<Int> {
189             return CoroutineScope(Dispatchers.Default)
190                 .async { mMeasurementManager.getMeasurementApiStatus() }
191                 .asListenableFuture()
192         }
193     }
194 
195     companion object {
196         /**
197          * Creates [MeasurementManagerFutures].
198          *
199          * @return MeasurementManagerFutures object. If the device is running an incompatible build,
200          *   the value returned is null.
201          */
202         @JvmStatic
fromnull203         fun from(context: Context): MeasurementManagerFutures? {
204             return obtain(context)?.let { Api33Ext5JavaImpl(it) }
205         }
206     }
207 }
208