1 /*
2  * Copyright (C) 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 android.adservices.customaudience;
18 
19 import static com.android.adservices.flags.Flags.FLAG_FLEDGE_SCHEDULE_CUSTOM_AUDIENCE_UPDATE_ENABLED;
20 
21 import android.adservices.common.AdServicesOutcomeReceiver;
22 import android.annotation.FlaggedApi;
23 import android.annotation.NonNull;
24 import android.net.Uri;
25 
26 import com.android.internal.util.Preconditions;
27 
28 import java.time.Duration;
29 import java.util.List;
30 import java.util.Objects;
31 import java.util.concurrent.Executor;
32 
33 /**
34  * The request object wrapping the required and optional parameters to schedule a deferred update
35  * for a buyer ad tech's custom audiences.
36  *
37  * <p>The on-device caller can specify information in a series of {@link PartialCustomAudience}
38  * objects that will be sent to the buyer ad tech's server after a designated minimum delay.
39  */
40 @FlaggedApi(FLAG_FLEDGE_SCHEDULE_CUSTOM_AUDIENCE_UPDATE_ENABLED)
41 public final class ScheduleCustomAudienceUpdateRequest {
42     @NonNull private final Uri mUpdateUri;
43     @NonNull private final Duration mMinDelay;
44     @NonNull private final List<PartialCustomAudience> mPartialCustomAudienceList;
45     private final boolean mShouldReplacePendingUpdates;
46 
ScheduleCustomAudienceUpdateRequest( @onNull ScheduleCustomAudienceUpdateRequest.Builder builder)47     private ScheduleCustomAudienceUpdateRequest(
48             @NonNull ScheduleCustomAudienceUpdateRequest.Builder builder) {
49         Objects.requireNonNull(builder);
50 
51         this.mUpdateUri = builder.mUpdateUri;
52         this.mMinDelay = builder.mMinDelay;
53         this.mPartialCustomAudienceList = builder.mPartialCustomAudienceList;
54         this.mShouldReplacePendingUpdates = builder.mShouldReplacePendingUpdates;
55     }
56 
57     /**
58      * Returns the {@link Uri} from which the update for the buyer's custom audiences will be
59      * fetched.
60      *
61      * <p>The {@link Uri} must use the same HTTPS site as the buyer ad tech's enrolled server.
62      */
63     @NonNull
getUpdateUri()64     public Uri getUpdateUri() {
65         return mUpdateUri;
66     }
67 
68     /**
69      * Returns the minimum {@link Duration} that the update will be deferred before the service
70      * fetches updates for the buyer ad tech's custom audiences.
71      */
72     @NonNull
getMinDelay()73     public Duration getMinDelay() {
74         return mMinDelay;
75     }
76 
77     /**
78      * Returns the list of {@link PartialCustomAudience} objects which are sent along with the
79      * request to download the updates for the buyer ad tech's custom audiences.
80      */
81     @NonNull
getPartialCustomAudienceList()82     public List<PartialCustomAudience> getPartialCustomAudienceList() {
83         return mPartialCustomAudienceList;
84     }
85 
86     /**
87      * Returns {@code true} if any pending scheduled updates should be canceled and replaced with
88      * the update detailed in the current {@link ScheduleCustomAudienceUpdateRequest}.
89      *
90      * <p>If this method returns {@code false} and there are previously requested updates still
91      * pending for the same buyer in the same app, a call to {@link
92      * CustomAudienceManager#scheduleCustomAudienceUpdate(ScheduleCustomAudienceUpdateRequest,
93      * Executor, AdServicesOutcomeReceiver)} with this {@link ScheduleCustomAudienceUpdateRequest}
94      * will fail.
95      */
shouldReplacePendingUpdates()96     public boolean shouldReplacePendingUpdates() {
97         return mShouldReplacePendingUpdates;
98     }
99 
100     /** Returns the hash of {@link ScheduleCustomAudienceUpdateRequest} object's data. */
101     @Override
hashCode()102     public int hashCode() {
103         return Objects.hash(
104                 mUpdateUri, mMinDelay, mPartialCustomAudienceList, mShouldReplacePendingUpdates);
105     }
106 
107     /**
108      * @return {@code true} only if two {@link ScheduleCustomAudienceUpdateRequest} objects contain
109      *     the same information.
110      */
111     @Override
equals(Object o)112     public boolean equals(Object o) {
113         if (this == o) return true;
114         if (!(o instanceof ScheduleCustomAudienceUpdateRequest that)) return false;
115         return mShouldReplacePendingUpdates == that.mShouldReplacePendingUpdates
116                 && mUpdateUri.equals(that.mUpdateUri)
117                 && mMinDelay.equals(that.mMinDelay)
118                 && mPartialCustomAudienceList.equals(that.mPartialCustomAudienceList);
119     }
120 
121     /**
122      * @return a human-readable representation of {@link ScheduleCustomAudienceUpdateRequest}.
123      */
124     @Override
toString()125     public String toString() {
126         return "ScheduleCustomAudienceUpdateRequest{"
127                 + "mUpdateUri="
128                 + mUpdateUri
129                 + ", mMinDelay="
130                 + mMinDelay
131                 + ", mPartialCustomAudienceList="
132                 + mPartialCustomAudienceList
133                 + ", mShouldReplacePendingUpdates="
134                 + mShouldReplacePendingUpdates
135                 + '}';
136     }
137 
138     /** Builder for {@link ScheduleCustomAudienceUpdateRequest} objects. */
139     @FlaggedApi(FLAG_FLEDGE_SCHEDULE_CUSTOM_AUDIENCE_UPDATE_ENABLED)
140     public static final class Builder {
141         @NonNull private Uri mUpdateUri;
142         @NonNull private Duration mMinDelay;
143         @NonNull private List<PartialCustomAudience> mPartialCustomAudienceList;
144         private boolean mShouldReplacePendingUpdates;
145 
146         /**
147          * Instantiates a builder for a {@link ScheduleCustomAudienceUpdateRequest} object.
148          *
149          * @param updateUri {@link Uri} of the buyer ad tech's server from which the updates for the
150          *     buyer's custom audiences will be fetched
151          * @param minDelay Minimum {@link Duration} for which the update should be deferred
152          * @param partialCustomAudienceList {@link List} of {@link PartialCustomAudience} objects
153          *     which will be sent to the buyer ad tech's server
154          */
Builder( @onNull Uri updateUri, @NonNull Duration minDelay, @NonNull List<PartialCustomAudience> partialCustomAudienceList)155         public Builder(
156                 @NonNull Uri updateUri,
157                 @NonNull Duration minDelay,
158                 @NonNull List<PartialCustomAudience> partialCustomAudienceList) {
159             this.mUpdateUri = Objects.requireNonNull(updateUri, "Update URI must not be null");
160             Objects.requireNonNull(minDelay, "Minimum delay must not be null");
161             Preconditions.checkArgument(
162                     !minDelay.isNegative(), "Minimum delay %d must not be negative", minDelay);
163             this.mMinDelay = minDelay;
164             this.mPartialCustomAudienceList =
165                     Objects.requireNonNull(
166                             partialCustomAudienceList,
167                             "Partial custom audience list must not be null");
168         }
169 
170         /**
171          * Sets the {@link Uri} from which the update for the buyer's custom audiences will be
172          * fetched.
173          *
174          * <p>The {@link Uri} must use the same HTTPS site as the buyer ad tech's enrolled server.
175          *
176          * <p>See {@link #getUpdateUri()} for more details.
177          */
178         @NonNull
setUpdateUri(@onNull Uri updateUri)179         public Builder setUpdateUri(@NonNull Uri updateUri) {
180             this.mUpdateUri = Objects.requireNonNull(updateUri, "Update URI must not be null");
181             return this;
182         }
183 
184         /**
185          * Sets the minimum {@link Duration} that the update will be deferred before the service
186          * fetches updates for the buyer ad tech's custom audiences.
187          *
188          * <p>This delay must not be a negative {@link Duration}.
189          *
190          * <p>See {@link #getMinDelay()} for more details.
191          */
192         @NonNull
setMinDelay(@onNull Duration minDelay)193         public Builder setMinDelay(@NonNull Duration minDelay) {
194             Objects.requireNonNull(minDelay, "Minimum delay must not be null");
195             Preconditions.checkArgument(
196                     !minDelay.isNegative(), "Minimum delay %d must not be negative", minDelay);
197             this.mMinDelay = minDelay;
198             return this;
199         }
200 
201         /**
202          * Sets the list of {@link PartialCustomAudience} objects that are sent to the buyer ad
203          * tech's server when making a request to download updates for the buyer's custom audiences.
204          *
205          * <p>See {@link #getPartialCustomAudienceList()} for more details.
206          */
207         @NonNull
setPartialCustomAudienceList( @onNull List<PartialCustomAudience> partialCustomAudienceList)208         public Builder setPartialCustomAudienceList(
209                 @NonNull List<PartialCustomAudience> partialCustomAudienceList) {
210             this.mPartialCustomAudienceList =
211                     Objects.requireNonNull(
212                             partialCustomAudienceList,
213                             "Partial custom audience list must not be null");
214             return this;
215         }
216 
217         /**
218          * Sets whether any pending scheduled updates should be deleted and replaced with this
219          * {@link ScheduleCustomAudienceUpdateRequest}.
220          *
221          * <p>By default, this setting is {@code false}.
222          *
223          * <p>See {@link #shouldReplacePendingUpdates()} for more details.
224          */
225         @NonNull
setShouldReplacePendingUpdates(boolean shouldReplacePendingUpdates)226         public Builder setShouldReplacePendingUpdates(boolean shouldReplacePendingUpdates) {
227             this.mShouldReplacePendingUpdates = shouldReplacePendingUpdates;
228             return this;
229         }
230 
231         /** Builds an instance of {@link ScheduleCustomAudienceUpdateRequest}. */
232         @NonNull
build()233         public ScheduleCustomAudienceUpdateRequest build() {
234             return new ScheduleCustomAudienceUpdateRequest(this);
235         }
236     }
237 }
238