1 /*
2  * Copyright 2024 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.signals
18 
19 import android.adservices.common.AdServicesPermissions
20 import android.annotation.SuppressLint
21 import android.content.Context
22 import android.util.Log
23 import androidx.annotation.RequiresPermission
24 import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
25 import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
26 
27 /** This class provides APIs for app and ad-SDKs to join / leave custom audiences. */
28 abstract class ProtectedSignalsManager internal constructor() {
29     /**
30      * The updateSignals API will retrieve a JSON from the URI that describes which signals to add
31      * or remove. This API also allows registering the encoder endpoint. The endpoint is used to
32      * download an encoding logic, which enables encoding the signals.
33      *
34      * <p>The top level keys for the JSON must correspond to one of 5 commands:
35      *
36      * <p>"put" - Adds a new signal, overwriting any existing signals with the same key. The value
37      * for this is a JSON object where the keys are base 64 strings corresponding to the key to put
38      * for and the values are base 64 string corresponding to the value to put.
39      *
40      * <p>"append" - Appends a new signal/signals to a time series of signals, removing the oldest
41      * signals to make room for the new ones if the size of the series exceeds the given maximum.
42      * The value for this is a JSON object where the keys are base 64 strings corresponding to the
43      * key to append to and the values are objects with two fields: "values" and "maxSignals" .
44      * "values" is a list of base 64 strings corresponding to signal values to append to the time
45      * series. "maxSignals" is the maximum number of values that are allowed in this timeseries. If
46      * the current number of signals associated with the key exceeds maxSignals the oldest signals
47      * will be removed. Note that you can append to a key added by put. Not that appending more than
48      * the maximum number of values will cause a failure.
49      *
50      * <p>"put_if_not_present" - Adds a new signal only if there are no existing signals with the
51      * same key. The value for this is a JSON object where the keys are base 64 strings
52      * corresponding to the key to put for and the values are base 64 string corresponding to the
53      * value to put.
54      *
55      * <p>"remove" - Removes the signal for a key. The value of this is a list of base 64 strings
56      * corresponding to the keys of signals that should be deleted.
57      *
58      * <p>"update_encoder" - Provides an action to update the endpoint, and a URI which can be used
59      * to retrieve an encoding logic. The sub-key for providing an update action is "action" and the
60      * values currently supported are:
61      * <ol>
62      * <li>"REGISTER" : Registers the encoder endpoint if provided for the first time or overwrites
63      *   the existing one with the newly provided endpoint. Providing the "endpoint" is required for
64      *   the "REGISTER" action.
65      * </ol>
66      *
67      * <p>The sub-key for providing an encoder endpoint is "endpoint" and the value is the URI
68      * string for the endpoint.
69      *
70      * <p>Key may only be operated on by one command per JSON. If two command attempt to operate on
71      * the same key, this method will through an {@link IllegalArgumentException}
72      *
73      * <p>This call fails with an {@link SecurityException} if
74      * <ol>
75      * <li>the {@code ownerPackageName} is not calling app's package name and/or
76      * <li>the buyer is not authorized to use the API.
77      * </ol>
78      *
79      * <p>This call fails with an {@link IllegalArgumentException} if
80      * <ol>
81      * <li>The JSON retrieved from the server is not valid.
82      * <li>The provided URI is invalid.
83      * </ol>
84      *
85      * <p>This call fails with {@link LimitExceededException} if the calling package exceeds the
86      * allowed rate limits and is throttled.
87      *
88      * <p>This call fails with an {@link IllegalStateException} if an internal service error is
89      * encountered.
90      */
91     @ExperimentalFeatures.Ext12OptIn
92     @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_PROTECTED_SIGNALS)
updateSignalsnull93     abstract suspend fun updateSignals(request: UpdateSignalsRequest)
94 
95     companion object {
96         private const val TAG = "ProtectedSignalsManager"
97 
98         /**
99          * Creates [ProtectedSignalsManager].
100          *
101          * @return ProtectedSignalsManager object. If the device is running an incompatible build,
102          *   the value returned is null.
103          */
104         @JvmStatic
105         @SuppressLint("NewApi")
106         @ExperimentalFeatures.Ext12OptIn
107         fun obtain(context: Context): ProtectedSignalsManager? {
108             return if (AdServicesInfo.adServicesVersion() >= 12) {
109                 Log.d(TAG, "Adservices version 12 detected, obtaining ProtectedSignalsManagerImpl.")
110                 ProtectedSignalsManagerImpl(
111                     android.adservices.signals.ProtectedSignalsManager.get(context)
112                 )
113             } else {
114                 Log.d(
115                     TAG,
116                     "Adservices less than 12, returning null for ProtectedSignalsManager.obtain."
117                 )
118                 null
119             }
120         }
121     }
122 }
123