| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.adservices.adselection; |
| |
| import android.adservices.common.AdSelectionSignals; |
| import android.adservices.common.AdTechIdentifier; |
| import android.annotation.NonNull; |
| import android.net.Uri; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import com.android.adservices.AdServicesParcelableUtil; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| /** |
| * Contains the configuration of the ad selection process. |
| * |
| * <p>Instances of this class are created by SDKs to be provided as arguments to the {@link |
| * AdSelectionManager#selectAds} and {@link AdSelectionManager#reportImpression} methods in {@link |
| * AdSelectionManager}. |
| */ |
| // TODO(b/233280314): investigate on adSelectionConfig optimization by merging mCustomAudienceBuyers |
| // and mPerBuyerSignals. |
| public final class AdSelectionConfig implements Parcelable { |
| /** |
| * {@link AdSelectionConfig} with empty values for each field. |
| * |
| * @hide |
| */ |
| @NonNull public static final AdSelectionConfig EMPTY = new AdSelectionConfig(); |
| |
| @NonNull private final AdTechIdentifier mSeller; |
| @NonNull private final Uri mDecisionLogicUri; |
| @NonNull private final List<AdTechIdentifier> mCustomAudienceBuyers; |
| @NonNull private final AdSelectionSignals mAdSelectionSignals; |
| @NonNull private final AdSelectionSignals mSellerSignals; |
| @NonNull private final Map<AdTechIdentifier, AdSelectionSignals> mPerBuyerSignals; |
| @NonNull private final Map<AdTechIdentifier, SignedContextualAds> mBuyerSignedContextualAds; |
| @NonNull private final Uri mTrustedScoringSignalsUri; |
| |
| @NonNull |
| public static final Creator<AdSelectionConfig> CREATOR = |
| new Creator<AdSelectionConfig>() { |
| @Override |
| public AdSelectionConfig createFromParcel(@NonNull Parcel in) { |
| Objects.requireNonNull(in); |
| return new AdSelectionConfig(in); |
| } |
| |
| @Override |
| public AdSelectionConfig[] newArray(int size) { |
| return new AdSelectionConfig[size]; |
| } |
| }; |
| |
| private AdSelectionConfig() { |
| this.mSeller = AdTechIdentifier.fromString(""); |
| this.mDecisionLogicUri = Uri.EMPTY; |
| this.mCustomAudienceBuyers = Collections.emptyList(); |
| this.mAdSelectionSignals = AdSelectionSignals.EMPTY; |
| this.mSellerSignals = AdSelectionSignals.EMPTY; |
| this.mPerBuyerSignals = Collections.emptyMap(); |
| this.mBuyerSignedContextualAds = Collections.emptyMap(); |
| this.mTrustedScoringSignalsUri = Uri.EMPTY; |
| } |
| |
| private AdSelectionConfig( |
| @NonNull AdTechIdentifier seller, |
| @NonNull Uri decisionLogicUri, |
| @NonNull List<AdTechIdentifier> customAudienceBuyers, |
| @NonNull AdSelectionSignals adSelectionSignals, |
| @NonNull AdSelectionSignals sellerSignals, |
| @NonNull Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals, |
| @NonNull Map<AdTechIdentifier, SignedContextualAds> perBuyerSignedContextualAds, |
| @NonNull Uri trustedScoringSignalsUri) { |
| this.mSeller = seller; |
| this.mDecisionLogicUri = decisionLogicUri; |
| this.mCustomAudienceBuyers = customAudienceBuyers; |
| this.mAdSelectionSignals = adSelectionSignals; |
| this.mSellerSignals = sellerSignals; |
| this.mPerBuyerSignals = perBuyerSignals; |
| this.mBuyerSignedContextualAds = perBuyerSignedContextualAds; |
| this.mTrustedScoringSignalsUri = trustedScoringSignalsUri; |
| } |
| |
| private AdSelectionConfig(@NonNull Parcel in) { |
| Objects.requireNonNull(in); |
| mSeller = AdTechIdentifier.CREATOR.createFromParcel(in); |
| mDecisionLogicUri = Uri.CREATOR.createFromParcel(in); |
| mCustomAudienceBuyers = in.createTypedArrayList(AdTechIdentifier.CREATOR); |
| mAdSelectionSignals = AdSelectionSignals.CREATOR.createFromParcel(in); |
| mSellerSignals = AdSelectionSignals.CREATOR.createFromParcel(in); |
| mPerBuyerSignals = |
| AdServicesParcelableUtil.readMapFromParcel( |
| in, AdTechIdentifier::fromString, AdSelectionSignals.class); |
| mBuyerSignedContextualAds = |
| AdServicesParcelableUtil.readMapFromParcel( |
| in, AdTechIdentifier::fromString, SignedContextualAds.class); |
| mTrustedScoringSignalsUri = Uri.CREATOR.createFromParcel(in); |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| Objects.requireNonNull(dest); |
| |
| mSeller.writeToParcel(dest, flags); |
| mDecisionLogicUri.writeToParcel(dest, flags); |
| dest.writeTypedList(mCustomAudienceBuyers); |
| mAdSelectionSignals.writeToParcel(dest, flags); |
| mSellerSignals.writeToParcel(dest, flags); |
| AdServicesParcelableUtil.writeMapToParcel(dest, mPerBuyerSignals); |
| AdServicesParcelableUtil.writeMapToParcel(dest, mBuyerSignedContextualAds); |
| mTrustedScoringSignalsUri.writeToParcel(dest, flags); |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (!(o instanceof AdSelectionConfig)) return false; |
| AdSelectionConfig that = (AdSelectionConfig) o; |
| return Objects.equals(mSeller, that.mSeller) |
| && Objects.equals(mDecisionLogicUri, that.mDecisionLogicUri) |
| && Objects.equals(mCustomAudienceBuyers, that.mCustomAudienceBuyers) |
| && Objects.equals(mAdSelectionSignals, that.mAdSelectionSignals) |
| && Objects.equals(mSellerSignals, that.mSellerSignals) |
| && Objects.equals(mPerBuyerSignals, that.mPerBuyerSignals) |
| && Objects.equals(mBuyerSignedContextualAds, that.mBuyerSignedContextualAds) |
| && Objects.equals(mTrustedScoringSignalsUri, that.mTrustedScoringSignalsUri); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash( |
| mSeller, |
| mDecisionLogicUri, |
| mCustomAudienceBuyers, |
| mAdSelectionSignals, |
| mSellerSignals, |
| mPerBuyerSignals, |
| mBuyerSignedContextualAds, |
| mTrustedScoringSignalsUri); |
| } |
| |
| /** |
| * @return a new builder instance created from this object's cloned data |
| * @hide |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder cloneToBuilder() { |
| return new AdSelectionConfig.Builder() |
| .setSeller(this.getSeller()) |
| .setBuyerSignedContextualAds(this.getBuyerSignedContextualAds()) |
| .setAdSelectionSignals(this.getAdSelectionSignals()) |
| .setCustomAudienceBuyers(this.getCustomAudienceBuyers()) |
| .setDecisionLogicUri(this.getDecisionLogicUri()) |
| .setPerBuyerSignals(this.getPerBuyerSignals()) |
| .setSellerSignals(this.getSellerSignals()) |
| .setTrustedScoringSignalsUri(this.getTrustedScoringSignalsUri()); |
| } |
| |
| /** @return a AdTechIdentifier of the seller, for example "www.example-ssp.com" */ |
| @NonNull |
| public AdTechIdentifier getSeller() { |
| return mSeller; |
| } |
| |
| /** |
| * @return the URI used to retrieve the JS code containing the seller/SSP scoreAd function used |
| * during the ad selection and reporting processes |
| */ |
| @NonNull |
| public Uri getDecisionLogicUri() { |
| return mDecisionLogicUri; |
| } |
| |
| /** |
| * @return a list of custom audience buyers allowed by the SSP to participate in the ad |
| * selection process |
| */ |
| @NonNull |
| public List<AdTechIdentifier> getCustomAudienceBuyers() { |
| return mCustomAudienceBuyers; |
| } |
| |
| /** |
| * @return JSON in an AdSelectionSignals object, fetched from the AdSelectionConfig and consumed |
| * by the JS logic fetched from the DSP, represents signals given to the participating |
| * buyers in the ad selection and reporting processes. |
| */ |
| @NonNull |
| public AdSelectionSignals getAdSelectionSignals() { |
| return mAdSelectionSignals; |
| } |
| |
| /** |
| * @return JSON in an AdSelectionSignals object, provided by the SSP and consumed by the JS |
| * logic fetched from the SSP, represents any information that the SSP used in the ad |
| * scoring process to tweak the results of the ad selection process (e.g. brand safety |
| * checks, excluded contextual ads). |
| */ |
| @NonNull |
| public AdSelectionSignals getSellerSignals() { |
| return mSellerSignals; |
| } |
| |
| /** |
| * @return a Map of buyers and AdSelectionSignals, fetched from the AdSelectionConfig and |
| * consumed by the JS logic fetched from the DSP, representing any information that each |
| * buyer would provide during ad selection to participants (such as bid floor, ad selection |
| * type, etc.) |
| */ |
| @NonNull |
| public Map<AdTechIdentifier, AdSelectionSignals> getPerBuyerSignals() { |
| return mPerBuyerSignals; |
| } |
| |
| /** |
| * @return a Map of buyers and corresponding Contextual Ads, these ads are expected to be |
| * pre-downloaded from the contextual path and injected into Ad Selection. |
| * @hide |
| */ |
| @NonNull |
| public Map<AdTechIdentifier, SignedContextualAds> getBuyerSignedContextualAds() { |
| return mBuyerSignedContextualAds; |
| } |
| |
| /** |
| * @return URI endpoint of sell-side trusted signal from which creative specific realtime |
| * information can be fetched from. |
| */ |
| @NonNull |
| public Uri getTrustedScoringSignalsUri() { |
| return mTrustedScoringSignalsUri; |
| } |
| |
| /** Builder for {@link AdSelectionConfig} object. */ |
| public static final class Builder { |
| private AdTechIdentifier mSeller; |
| private Uri mDecisionLogicUri; |
| private List<AdTechIdentifier> mCustomAudienceBuyers; |
| private AdSelectionSignals mAdSelectionSignals = AdSelectionSignals.EMPTY; |
| private AdSelectionSignals mSellerSignals = AdSelectionSignals.EMPTY; |
| private Map<AdTechIdentifier, AdSelectionSignals> mPerBuyerSignals = Collections.emptyMap(); |
| private Map<AdTechIdentifier, SignedContextualAds> mBuyerSignedContextualAds = |
| Collections.emptyMap(); |
| private Uri mTrustedScoringSignalsUri; |
| |
| public Builder() {} |
| |
| /** |
| * Sets the seller identifier. |
| * |
| * <p>See {@link #getSeller()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setSeller(@NonNull AdTechIdentifier seller) { |
| Objects.requireNonNull(seller); |
| |
| this.mSeller = seller; |
| return this; |
| } |
| |
| /** |
| * Sets the URI used to fetch decision logic for use in the ad selection process. Decision |
| * URI could be either of the two schemas: |
| * |
| * <ul> |
| * <li><b>HTTPS:</b> HTTPS URIs have to be absolute URIs where the host matches the {@code |
| * seller} |
| * <li><b>Ad Selection Prebuilt:</b> Ad Selection Service URIs follow {@code |
| * ad-selection-prebuilt://ad-selection/<name>?<script-generation-parameters>} format. |
| * FLEDGE generates the appropriate JS script without the need for a network call. |
| * <p>Available prebuilt scripts: |
| * <ul> |
| * <li><b>{@code highest-bid-wins} for {@code scoreAds} and {@code |
| * reportResult}:</b> This JS picks the ad with the highest bid for scoring. For |
| * reporting, the given URI is parameterized with {@code render_uri} and {@code |
| * bid}. Below parameter(s) are required to use this prebuilt: |
| * <ul> |
| * <li><b>{@code reportingUrl}:</b> Base reporting uri that will be |
| * parameterized later with {@code render_uri} and {@code bid} |
| * </ul> |
| * <p>Ex. If your base reporting URL is "https://www.ssp.com" then, {@code |
| * ad-selection-prebuilt://ad-selection/highest-bid-wins/?reportingUrl=https://www.ssp.com} |
| * </ul> |
| * </ul> |
| * |
| * <p>See {@link #getDecisionLogicUri()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setDecisionLogicUri(@NonNull Uri decisionLogicUri) { |
| Objects.requireNonNull(decisionLogicUri); |
| |
| this.mDecisionLogicUri = decisionLogicUri; |
| return this; |
| } |
| |
| /** |
| * Sets the list of allowed buyers. |
| * |
| * <p>See {@link #getCustomAudienceBuyers()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setCustomAudienceBuyers( |
| @NonNull List<AdTechIdentifier> customAudienceBuyers) { |
| Objects.requireNonNull(customAudienceBuyers); |
| |
| this.mCustomAudienceBuyers = customAudienceBuyers; |
| return this; |
| } |
| |
| /** |
| * Sets the signals provided to buyers during ad selection bid generation. |
| * |
| * <p>If not set, defaults to the empty JSON. |
| * |
| * <p>See {@link #getAdSelectionSignals()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setAdSelectionSignals( |
| @NonNull AdSelectionSignals adSelectionSignals) { |
| Objects.requireNonNull(adSelectionSignals); |
| |
| this.mAdSelectionSignals = adSelectionSignals; |
| return this; |
| } |
| |
| /** |
| * Set the signals used to modify ad selection results. |
| * |
| * <p>If not set, defaults to the empty JSON. |
| * |
| * <p>See {@link #getSellerSignals()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setSellerSignals( |
| @NonNull AdSelectionSignals sellerSignals) { |
| Objects.requireNonNull(sellerSignals); |
| |
| this.mSellerSignals = sellerSignals; |
| return this; |
| } |
| |
| /** |
| * Sets the signals provided by each buyer during ad selection. |
| * |
| * <p>If not set, defaults to an empty map. |
| * |
| * <p>See {@link #getPerBuyerSignals()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setPerBuyerSignals( |
| @NonNull Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals) { |
| Objects.requireNonNull(perBuyerSignals); |
| |
| this.mPerBuyerSignals = perBuyerSignals; |
| return this; |
| } |
| |
| /** |
| * Sets the contextual Ads corresponding to each buyer during ad selection. |
| * |
| * <p>If not set, defaults to an empty map. |
| * |
| * <p>See {@link #getBuyerSignedContextualAds()} ()} for more details. |
| * |
| * @hide |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setBuyerSignedContextualAds( |
| @NonNull Map<AdTechIdentifier, SignedContextualAds> buyerSignedContextualAds) { |
| Objects.requireNonNull(buyerSignedContextualAds); |
| |
| this.mBuyerSignedContextualAds = buyerSignedContextualAds; |
| return this; |
| } |
| |
| /** |
| * Sets the URI endpoint of sell-side trusted signal from which creative specific realtime |
| * information can be fetched from. |
| * |
| * <p>If {@link Uri#EMPTY} is passed then network call will be skipped and {@link |
| * AdSelectionSignals#EMPTY} will be passed to ad selection. |
| * |
| * <p>See {@link #getTrustedScoringSignalsUri()} for more details. |
| */ |
| @NonNull |
| public AdSelectionConfig.Builder setTrustedScoringSignalsUri( |
| @NonNull Uri trustedScoringSignalsUri) { |
| Objects.requireNonNull(trustedScoringSignalsUri); |
| |
| this.mTrustedScoringSignalsUri = trustedScoringSignalsUri; |
| return this; |
| } |
| |
| /** |
| * Builds an {@link AdSelectionConfig} instance. |
| * |
| * @throws NullPointerException if any required params are null |
| */ |
| @NonNull |
| public AdSelectionConfig build() { |
| Objects.requireNonNull(mSeller); |
| Objects.requireNonNull(mDecisionLogicUri); |
| Objects.requireNonNull(mCustomAudienceBuyers); |
| Objects.requireNonNull(mAdSelectionSignals); |
| Objects.requireNonNull(mSellerSignals); |
| Objects.requireNonNull(mPerBuyerSignals); |
| Objects.requireNonNull(mBuyerSignedContextualAds); |
| Objects.requireNonNull(mTrustedScoringSignalsUri); |
| return new AdSelectionConfig( |
| mSeller, |
| mDecisionLogicUri, |
| mCustomAudienceBuyers, |
| mAdSelectionSignals, |
| mSellerSignals, |
| mPerBuyerSignals, |
| mBuyerSignedContextualAds, |
| mTrustedScoringSignalsUri); |
| } |
| } |
| } |