| /* |
| * 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 com.android.adservices.service.measurement; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.net.Uri; |
| import android.util.Pair; |
| |
| import com.android.adservices.LogUtil; |
| import com.android.adservices.service.Flags; |
| import com.android.adservices.service.FlagsFactory; |
| import com.android.adservices.service.measurement.aggregation.AggregatableAttributionSource; |
| import com.android.adservices.service.measurement.noising.Combinatorics; |
| import com.android.adservices.service.measurement.noising.SourceNoiseHandler; |
| import com.android.adservices.service.measurement.reporting.EventReportWindowCalcDelegate; |
| import com.android.adservices.service.measurement.util.UnsignedLong; |
| import com.android.adservices.service.measurement.util.Validation; |
| import com.android.internal.annotations.VisibleForTesting; |
| |
| import com.google.common.collect.ImmutableMultiset; |
| |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.Optional; |
| import java.util.TreeMap; |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * POJO for Source. |
| */ |
| public class Source { |
| |
| private String mId; |
| private UnsignedLong mEventId; |
| private Uri mPublisher; |
| @EventSurfaceType private int mPublisherType; |
| private List<Uri> mAppDestinations; |
| private List<Uri> mWebDestinations; |
| private String mEnrollmentId; |
| private Uri mRegistrant; |
| private SourceType mSourceType; |
| private long mPriority; |
| @Status private int mStatus; |
| private long mEventTime; |
| private long mExpiryTime; |
| @Nullable private Long mEventReportWindow; |
| @Nullable private String mEventReportWindows; |
| private long mAggregatableReportWindow; |
| private List<UnsignedLong> mAggregateReportDedupKeys; |
| private List<UnsignedLong> mEventReportDedupKeys; |
| @AttributionMode private int mAttributionMode; |
| private long mInstallAttributionWindow; |
| private long mInstallCooldownWindow; |
| @Nullable private UnsignedLong mDebugKey; |
| private boolean mIsInstallAttributed; |
| private boolean mIsDebugReporting; |
| private String mFilterDataString; |
| @Nullable private String mSharedFilterDataKeys; |
| private FilterMap mFilterData; |
| private String mAggregateSource; |
| private int mAggregateContributions; |
| private Optional<AggregatableAttributionSource> mAggregatableAttributionSource; |
| private boolean mAdIdPermission; |
| private boolean mArDebugPermission; |
| @Nullable private String mRegistrationId; |
| @Nullable private String mSharedAggregationKeys; |
| @Nullable private Long mInstallTime; |
| @Nullable private String mParentId; |
| @Nullable private String mDebugJoinKey; |
| @Nullable private List<AttributedTrigger> mAttributedTriggers; |
| @Nullable private ReportSpec mFlexEventReportSpec; |
| @Nullable private String mTriggerSpecsString; |
| @Nullable private Integer mMaxEventLevelReports; |
| @Nullable private String mEventAttributionStatusString; |
| @Nullable private String mPrivacyParametersString = null; |
| @Nullable private String mPlatformAdId; |
| @Nullable private String mDebugAdId; |
| private Uri mRegistrationOrigin; |
| private boolean mCoarseEventReportDestinations; |
| @Nullable private UnsignedLong mSharedDebugKey; |
| private List<Pair<Long, Long>> mParsedEventReportWindows; |
| |
| /** |
| * Parses and returns the event_report_windows Returns null if parsing fails or if there is no |
| * windows provided by user. |
| */ |
| @Nullable |
| public List<Pair<Long, Long>> parsedProcessedEventReportWindows() { |
| if (mParsedEventReportWindows != null) { |
| return mParsedEventReportWindows; |
| } |
| if (mEventReportWindows == null) { |
| return null; |
| } |
| |
| List<Pair<Long, Long>> rawWindows = parseEventReportWindows(mEventReportWindows); |
| if (rawWindows == null) { |
| return null; |
| } |
| // Append Event Time |
| mParsedEventReportWindows = new ArrayList<>(); |
| |
| for (Pair<Long, Long> window : rawWindows) { |
| mParsedEventReportWindows.add( |
| new Pair<>(mEventTime + window.first, mEventTime + window.second)); |
| } |
| return mParsedEventReportWindows; |
| } |
| |
| /** |
| * Returns parsed or default value of event report windows. |
| * |
| * @param eventReportWindows string to be parsed |
| * @param sourceType Source's Type |
| * @param expiryDelta relative expiry value |
| * @param flags Flags |
| * @return parsed or default value |
| */ |
| @Nullable |
| public static List<Pair<Long, Long>> getOrDefaultEventReportWindows( |
| @Nullable String eventReportWindows, |
| @NonNull SourceType sourceType, |
| long expiryDelta, |
| @NonNull Flags flags) { |
| if (eventReportWindows == null) { |
| return getDefaultEventReportWindows(expiryDelta, sourceType, flags); |
| } |
| return parseEventReportWindows(eventReportWindows); |
| } |
| |
| /** Parses the provided eventReportWindows. Returns null if parsing fails */ |
| @Nullable |
| public static List<Pair<Long, Long>> parseEventReportWindows( |
| @NonNull String eventReportWindows) { |
| List<Pair<Long, Long>> result = new ArrayList<>(); |
| try { |
| JSONObject jsonObject = new JSONObject(eventReportWindows); |
| long startDuration = 0; |
| if (!jsonObject.isNull("start_time")) { |
| startDuration = jsonObject.getLong("start_time"); |
| } |
| JSONArray endTimesJSON = jsonObject.getJSONArray("end_times"); |
| |
| for (int i = 0; i < endTimesJSON.length(); i++) { |
| long endDuration = endTimesJSON.getLong(i); |
| Pair<Long, Long> window = new Pair<>(startDuration, endDuration); |
| result.add(window); |
| startDuration = endDuration; |
| } |
| } catch (JSONException e) { |
| LogUtil.e(e, "Invalid JSON encountered: event_report_windows"); |
| return null; |
| } |
| return result; |
| } |
| |
| private static List<Pair<Long, Long>> getDefaultEventReportWindows( |
| long expiryDelta, SourceType sourceType, Flags flags) { |
| List<Pair<Long, Long>> result = new ArrayList<>(); |
| List<Long> defaultEarlyWindows = |
| EventReportWindowCalcDelegate.getDefaultEarlyReportingWindows(sourceType, false); |
| List<Long> earlyWindows = |
| new EventReportWindowCalcDelegate(flags) |
| .getConfiguredOrDefaultEarlyReportingWindows( |
| sourceType, defaultEarlyWindows, false); |
| long windowStart = 0; |
| for (long earlyWindow : earlyWindows) { |
| if (earlyWindow >= expiryDelta) { |
| continue; |
| } |
| result.add(new Pair<>(windowStart, earlyWindow)); |
| windowStart = earlyWindow; |
| } |
| result.add(new Pair<>(windowStart, expiryDelta)); |
| return result; |
| } |
| |
| /** |
| * Checks if the source has valid information gain |
| * |
| * @param flags flag values |
| */ |
| public boolean hasValidInformationGain(@NonNull Flags flags) { |
| return isFlexLiteApiValueValid(flags) && isFlexEventApiValueValid(flags); |
| } |
| |
| private boolean isFlexLiteApiValueValid(Flags flags) { |
| if (!flags.getMeasurementFlexLiteAPIEnabled() |
| || (mEventReportWindows == null && mMaxEventLevelReports == null)) { |
| return true; |
| } |
| double informationGainThreshold = |
| mSourceType == SourceType.EVENT |
| ? flags.getMeasurementFlexApiMaxInformationGainEvent() |
| : flags.getMeasurementFlexApiMaxInformationGainNavigation(); |
| |
| EventReportWindowCalcDelegate eventReportWindowCalcDelegate = |
| new EventReportWindowCalcDelegate(flags); |
| boolean installCase = SourceNoiseHandler.isInstallDetectionEnabled(this); |
| long numStates = |
| Combinatorics.getNumStatesArithmetic( |
| eventReportWindowCalcDelegate.getMaxReportCount(this, installCase), |
| getTriggerDataCardinality(), |
| eventReportWindowCalcDelegate.getReportingWindowCountForNoising( |
| this, installCase)); |
| double flipProbability = Combinatorics.getFlipProbability(numStates); |
| |
| return Combinatorics.getInformationGain(numStates, flipProbability) |
| <= informationGainThreshold; |
| } |
| |
| /** Returns true is manual event reporting windows are set otherwise false; */ |
| public boolean hasManualEventReportWindows() { |
| return getEventReportWindows() != null; |
| } |
| |
| @IntDef(value = {Status.ACTIVE, Status.IGNORED, Status.MARKED_TO_DELETE}) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface Status { |
| int ACTIVE = 0; |
| int IGNORED = 1; |
| int MARKED_TO_DELETE = 2; |
| } |
| |
| @IntDef(value = { |
| AttributionMode.UNASSIGNED, |
| AttributionMode.TRUTHFULLY, |
| AttributionMode.NEVER, |
| AttributionMode.FALSELY, |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface AttributionMode { |
| int UNASSIGNED = 0; |
| int TRUTHFULLY = 1; |
| int NEVER = 2; |
| int FALSELY = 3; |
| } |
| |
| public enum SourceType { |
| EVENT("event"), |
| NAVIGATION("navigation"); |
| |
| private final String mValue; |
| |
| SourceType(String value) { |
| mValue = value; |
| } |
| |
| public String getValue() { |
| return mValue; |
| } |
| } |
| |
| private Source() { |
| mEventReportDedupKeys = new ArrayList<>(); |
| mAggregateReportDedupKeys = new ArrayList<>(); |
| mStatus = Status.ACTIVE; |
| mSourceType = SourceType.EVENT; |
| // Making this default explicit since it anyway would occur on an uninitialised int field. |
| mPublisherType = EventSurfaceType.APP; |
| mAttributionMode = AttributionMode.UNASSIGNED; |
| mIsInstallAttributed = false; |
| mIsDebugReporting = false; |
| } |
| |
| /** Class for storing fake report data. */ |
| public static class FakeReport { |
| private final UnsignedLong mTriggerData; |
| private final long mReportingTime; |
| private final List<Uri> mDestinations; |
| |
| public FakeReport(UnsignedLong triggerData, long reportingTime, List<Uri> destinations) { |
| mTriggerData = triggerData; |
| mReportingTime = reportingTime; |
| mDestinations = destinations; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (!(o instanceof FakeReport)) return false; |
| FakeReport that = (FakeReport) o; |
| return Objects.equals(mTriggerData, that.mTriggerData) |
| && mReportingTime == that.mReportingTime |
| && Objects.equals(mDestinations, that.mDestinations); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(mTriggerData, mReportingTime, mDestinations); |
| } |
| |
| public long getReportingTime() { |
| return mReportingTime; |
| } |
| |
| public UnsignedLong getTriggerData() { |
| return mTriggerData; |
| } |
| |
| public List<Uri> getDestinations() { |
| return mDestinations; |
| } |
| } |
| |
| /** |
| * Range of trigger metadata: [0, cardinality). |
| * |
| * @return Cardinality of {@link Trigger} metadata |
| */ |
| public int getTriggerDataCardinality() { |
| return mSourceType == SourceType.EVENT |
| ? PrivacyParams.EVENT_TRIGGER_DATA_CARDINALITY |
| : PrivacyParams.getNavigationTriggerDataCardinality(); |
| } |
| |
| /** |
| * @return the list of attributed triggers |
| */ |
| @Nullable |
| public List<AttributedTrigger> getAttributedTriggers() { |
| return mAttributedTriggers; |
| } |
| |
| /** |
| * @return the JSON encoded current trigger status |
| */ |
| @NonNull |
| public String attributedTriggersToJson() { |
| JSONArray jsonArray = new JSONArray(); |
| for (AttributedTrigger trigger : mAttributedTriggers) { |
| jsonArray.put(trigger.encodeToJson()); |
| } |
| return jsonArray.toString(); |
| } |
| |
| /** |
| * @return the JSON encoded current trigger status |
| */ |
| @NonNull |
| public String attributedTriggersToJsonFlexApi() { |
| JSONArray jsonArray = new JSONArray(); |
| for (AttributedTrigger trigger : mAttributedTriggers) { |
| jsonArray.put(trigger.encodeToJsonFlexApi()); |
| } |
| return jsonArray.toString(); |
| } |
| |
| /** |
| * @return the flex event report specifications |
| */ |
| @Nullable |
| public ReportSpec getFlexEventReportSpec() { |
| return mFlexEventReportSpec; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (!(obj instanceof Source)) { |
| return false; |
| } |
| Source source = (Source) obj; |
| return Objects.equals(mPublisher, source.mPublisher) |
| && mPublisherType == source.mPublisherType |
| && areEqualNullableDestinations(mAppDestinations, source.mAppDestinations) |
| && areEqualNullableDestinations(mWebDestinations, source.mWebDestinations) |
| && Objects.equals(mEnrollmentId, source.mEnrollmentId) |
| && mPriority == source.mPriority |
| && mStatus == source.mStatus |
| && mExpiryTime == source.mExpiryTime |
| && Objects.equals(mEventReportWindow, source.mEventReportWindow) |
| && Objects.equals(mEventReportWindows, source.mEventReportWindows) |
| && Objects.equals(mAggregatableReportWindow, source.mAggregatableReportWindow) |
| && mEventTime == source.mEventTime |
| && mAdIdPermission == source.mAdIdPermission |
| && mArDebugPermission == source.mArDebugPermission |
| && Objects.equals(mEventId, source.mEventId) |
| && Objects.equals(mDebugKey, source.mDebugKey) |
| && mSourceType == source.mSourceType |
| && Objects.equals(mEventReportDedupKeys, source.mEventReportDedupKeys) |
| && Objects.equals(mAggregateReportDedupKeys, source.mAggregateReportDedupKeys) |
| && Objects.equals(mRegistrant, source.mRegistrant) |
| && mAttributionMode == source.mAttributionMode |
| && mIsDebugReporting == source.mIsDebugReporting |
| && Objects.equals(mFilterDataString, source.mFilterDataString) |
| && Objects.equals(mSharedFilterDataKeys, source.mSharedFilterDataKeys) |
| && Objects.equals(mAggregateSource, source.mAggregateSource) |
| && mAggregateContributions == source.mAggregateContributions |
| && Objects.equals( |
| mAggregatableAttributionSource, source.mAggregatableAttributionSource) |
| && Objects.equals(mRegistrationId, source.mRegistrationId) |
| && Objects.equals(mSharedAggregationKeys, source.mSharedAggregationKeys) |
| && Objects.equals(mParentId, source.mParentId) |
| && Objects.equals(mInstallTime, source.mInstallTime) |
| && Objects.equals(mDebugJoinKey, source.mDebugJoinKey) |
| && Objects.equals(mPlatformAdId, source.mPlatformAdId) |
| && Objects.equals(mDebugAdId, source.mDebugAdId) |
| && Objects.equals(mRegistrationOrigin, source.mRegistrationOrigin) |
| && mCoarseEventReportDestinations == source.mCoarseEventReportDestinations |
| && Objects.equals(mAttributedTriggers, source.mAttributedTriggers) |
| && Objects.equals(mFlexEventReportSpec, source.mFlexEventReportSpec) |
| && Objects.equals(mTriggerSpecsString, source.mTriggerSpecsString) |
| && Objects.equals(mMaxEventLevelReports, source.mMaxEventLevelReports) |
| && Objects.equals( |
| mEventAttributionStatusString, source.mEventAttributionStatusString) |
| && Objects.equals(mPrivacyParametersString, source.mPrivacyParametersString) |
| && Objects.equals(mSharedDebugKey, source.mSharedDebugKey); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash( |
| mId, |
| mPublisher, |
| mPublisherType, |
| mAppDestinations, |
| mWebDestinations, |
| mEnrollmentId, |
| mPriority, |
| mStatus, |
| mExpiryTime, |
| mEventReportWindow, |
| mEventReportWindows, |
| mAggregatableReportWindow, |
| mEventTime, |
| mEventId, |
| mSourceType, |
| mEventReportDedupKeys, |
| mAggregateReportDedupKeys, |
| mFilterDataString, |
| mSharedFilterDataKeys, |
| mAggregateSource, |
| mAggregateContributions, |
| mAggregatableAttributionSource, |
| mDebugKey, |
| mAdIdPermission, |
| mArDebugPermission, |
| mRegistrationId, |
| mSharedAggregationKeys, |
| mInstallTime, |
| mDebugJoinKey, |
| mPlatformAdId, |
| mDebugAdId, |
| mRegistrationOrigin, |
| mDebugJoinKey, |
| mAttributedTriggers, |
| mFlexEventReportSpec, |
| mTriggerSpecsString, |
| mMaxEventLevelReports, |
| mEventAttributionStatusString, |
| mPrivacyParametersString, |
| mCoarseEventReportDestinations, |
| mSharedDebugKey); |
| } |
| |
| public void setAttributionMode(@AttributionMode int attributionMode) { |
| mAttributionMode = attributionMode; |
| } |
| |
| /** |
| * Retrieve the attribution destinations corresponding to their destination type. |
| * |
| * @return a list of Uris. |
| */ |
| public List<Uri> getAttributionDestinations(@EventSurfaceType int destinationType) { |
| return destinationType == EventSurfaceType.APP ? mAppDestinations : mWebDestinations; |
| } |
| |
| /** |
| * Unique identifier for the {@link Source}. |
| */ |
| public String getId() { |
| return mId; |
| } |
| |
| /** |
| * Identifier provided by the registrant. |
| */ |
| public UnsignedLong getEventId() { |
| return mEventId; |
| } |
| |
| /** |
| * Priority of the {@link Source}. |
| */ |
| public long getPriority() { |
| return mPriority; |
| } |
| |
| /** |
| * Ad Tech enrollment ID |
| */ |
| public String getEnrollmentId() { |
| return mEnrollmentId; |
| } |
| |
| /** Uri which registered the {@link Source}. */ |
| public Uri getPublisher() { |
| return mPublisher; |
| } |
| |
| /** The publisher type (e.g., app or web) {@link Source}. */ |
| @EventSurfaceType |
| public int getPublisherType() { |
| return mPublisherType; |
| } |
| |
| /** Uris for the {@link Trigger}'s app destinations. */ |
| @Nullable |
| public List<Uri> getAppDestinations() { |
| return mAppDestinations; |
| } |
| |
| /** Uris for the {@link Trigger}'s web destinations. */ |
| @Nullable |
| public List<Uri> getWebDestinations() { |
| return mWebDestinations; |
| } |
| |
| /** |
| * Type of {@link Source}. Values: Event, Navigation. |
| */ |
| public SourceType getSourceType() { |
| return mSourceType; |
| } |
| |
| /** Time when {@link Source} will expire. */ |
| public long getExpiryTime() { |
| return mExpiryTime; |
| } |
| |
| /** Returns Event report window */ |
| public Long getEventReportWindow() { |
| return mEventReportWindow; |
| } |
| |
| /** |
| * Time when {@link Source} event report window will expire. (Appends the Event Time to window) |
| */ |
| public Long getProcessedEventReportWindow() { |
| if (mEventReportWindow == null) { |
| return null; |
| } |
| // TODO(b/290098169): Cleanup after a few releases |
| // Handling cases where ReportWindow is already stored as mEventTime + mEventReportWindow |
| if (mEventReportWindow > mEventTime) { |
| return mEventReportWindow; |
| } else { |
| return mEventTime + mEventReportWindow; |
| } |
| } |
| |
| /** JSON string for event report windows */ |
| public String getEventReportWindows() { |
| return mEventReportWindows; |
| } |
| |
| /** Time when {@link Source} aggregate report window will expire. */ |
| public long getAggregatableReportWindow() { |
| return mAggregatableReportWindow; |
| } |
| |
| /** Debug key of {@link Source}. */ |
| @Nullable |
| public UnsignedLong getDebugKey() { |
| return mDebugKey; |
| } |
| |
| /** |
| * Time the event occurred. |
| */ |
| public long getEventTime() { |
| return mEventTime; |
| } |
| |
| /** Is Ad ID Permission Enabled. */ |
| public boolean hasAdIdPermission() { |
| return mAdIdPermission; |
| } |
| |
| /** Is Ar Debug Permission Enabled. */ |
| public boolean hasArDebugPermission() { |
| return mArDebugPermission; |
| } |
| |
| /** List of dedup keys for the attributed {@link Trigger}. */ |
| public List<UnsignedLong> getEventReportDedupKeys() { |
| return mEventReportDedupKeys; |
| } |
| |
| /** List of dedup keys used for generating Aggregate Reports. */ |
| public List<UnsignedLong> getAggregateReportDedupKeys() { |
| return mAggregateReportDedupKeys; |
| } |
| |
| /** Current status of the {@link Source}. */ |
| @Status |
| public int getStatus() { |
| return mStatus; |
| } |
| |
| /** |
| * Registrant of this source, primarily an App. |
| */ |
| public Uri getRegistrant() { |
| return mRegistrant; |
| } |
| |
| /** Selected mode for attribution. Values: Truthfully, Never, Falsely. */ |
| @AttributionMode |
| public int getAttributionMode() { |
| return mAttributionMode; |
| } |
| |
| /** |
| * Attribution window for install events. |
| */ |
| public long getInstallAttributionWindow() { |
| return mInstallAttributionWindow; |
| } |
| |
| /** |
| * Cooldown for attributing post-install {@link Trigger} events. |
| */ |
| public long getInstallCooldownWindow() { |
| return mInstallCooldownWindow; |
| } |
| |
| /** |
| * Is an App-install attributed to the {@link Source}. |
| */ |
| public boolean isInstallAttributed() { |
| return mIsInstallAttributed; |
| } |
| |
| /** Is Ad Tech Opt-in to Debug Reporting {@link Source}. */ |
| public boolean isDebugReporting() { |
| return mIsDebugReporting; |
| } |
| |
| /** |
| * Check whether the parameter of flexible event API is valid or not. Currently, only max |
| * information gain is check because of the computation is complicated. Other straightforward |
| * value errors will be show in the debug log using LogUtil |
| * |
| * @return whether the parameters of flexible are valid |
| */ |
| public boolean isFlexEventApiValueValid(Flags flags) { |
| if (!flags.getMeasurementFlexibleEventReportingApiEnabled() |
| || mFlexEventReportSpec == null) { |
| return true; |
| } |
| double informationGainThreshold = |
| mSourceType == SourceType.EVENT |
| ? flags.getMeasurementFlexApiMaxInformationGainEvent() |
| : flags.getMeasurementFlexApiMaxInformationGainNavigation(); |
| |
| if (mFlexEventReportSpec.getInformationGain() > informationGainThreshold) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Returns aggregate filter data string used for aggregation. aggregate filter data json is a |
| * JSONObject in Attribution-Reporting-Register-Source header. Example: |
| * Attribution-Reporting-Register-Source: { // some other fields. "filter_data" : { |
| * "conversion_subdomain": ["electronics.megastore"], "product": ["1234", "2345"], "ctid": |
| * ["id"], ...... } } |
| */ |
| public String getFilterDataString() { |
| return mFilterDataString; |
| } |
| |
| /** |
| * Returns the shared filter data keys of the source as a unique list of strings. Example: |
| * ["click_duration", "campaign_type"] |
| */ |
| @Nullable |
| public String getSharedFilterDataKeys() { |
| return mSharedFilterDataKeys; |
| } |
| |
| /** |
| * Returns aggregate source string used for aggregation. aggregate source json is a JSONArray. |
| * Example: [{ // Generates a "0x159" key piece (low order bits of the key) named // |
| * "campaignCounts" "id": "campaignCounts", "key_piece": "0x159", // User saw ad from campaign |
| * 345 (out of 511) }, { // Generates a "0x5" key piece (low order bits of the key) named |
| * "geoValue" "id": "geoValue", // Source-side geo region = 5 (US), out of a possible ~100 |
| * regions. "key_piece": "0x5", }] |
| */ |
| public String getAggregateSource() { |
| return mAggregateSource; |
| } |
| |
| /** |
| * Returns the current sum of values the source contributed to aggregatable reports. |
| */ |
| public int getAggregateContributions() { |
| return mAggregateContributions; |
| } |
| |
| /** |
| * Returns the AggregatableAttributionSource object, which is constructed using the aggregate |
| * source string and aggregate filter data string in Source. |
| * |
| * @deprecated use {@link #getAggregatableAttributionSourceV2(Trigger)} instead. |
| */ |
| @Deprecated |
| public Optional<AggregatableAttributionSource> getAggregatableAttributionSource() |
| throws JSONException { |
| if (mAggregatableAttributionSource == null) { |
| if (mAggregateSource == null) { |
| mAggregatableAttributionSource = Optional.empty(); |
| return mAggregatableAttributionSource; |
| } |
| JSONObject jsonObject = new JSONObject(mAggregateSource); |
| TreeMap<String, BigInteger> aggregateSourceMap = new TreeMap<>(); |
| Iterator<String> keys = jsonObject.keys(); |
| while (keys.hasNext()) { |
| String key = keys.next(); |
| // Remove "0x" prefix. |
| String hexString = jsonObject.getString(key).substring(2); |
| BigInteger bigInteger = new BigInteger(hexString, 16); |
| aggregateSourceMap.put(key, bigInteger); |
| } |
| AggregatableAttributionSource aggregatableAttributionSource = |
| new AggregatableAttributionSource.Builder() |
| .setAggregatableSource(aggregateSourceMap) |
| .setFilterMap(getFilterData()) |
| .build(); |
| mAggregatableAttributionSource = Optional.of(aggregatableAttributionSource); |
| } |
| |
| return mAggregatableAttributionSource; |
| } |
| |
| /** |
| * Returns the AggregatableAttributionSource object, which is constructed using the aggregate |
| * source string and aggregate filter data string in Source. |
| */ |
| public Optional<AggregatableAttributionSource> getAggregatableAttributionSourceV2( |
| @NonNull Trigger trigger) throws JSONException { |
| if (mAggregateSource == null) { |
| return Optional.empty(); |
| } |
| JSONObject jsonObject = new JSONObject(mAggregateSource); |
| TreeMap<String, BigInteger> aggregateSourceMap = new TreeMap<>(); |
| for (String key : jsonObject.keySet()) { |
| // Remove "0x" prefix. |
| String hexString = jsonObject.getString(key).substring(2); |
| BigInteger bigInteger = new BigInteger(hexString, 16); |
| aggregateSourceMap.put(key, bigInteger); |
| } |
| return Optional.of( |
| new AggregatableAttributionSource.Builder() |
| .setAggregatableSource(aggregateSourceMap) |
| .setFilterMap(getFilterData(trigger)) |
| .build()); |
| } |
| |
| /** Returns the registration id. */ |
| @Nullable |
| public String getRegistrationId() { |
| return mRegistrationId; |
| } |
| |
| /** |
| * Returns the shared aggregation keys of the source as a unique list of strings. Example: |
| * [“campaignCounts”] |
| */ |
| @Nullable |
| public String getSharedAggregationKeys() { |
| return mSharedAggregationKeys; |
| } |
| |
| /** Returns the install time of the source which is the same value as event time. */ |
| @Nullable |
| public Long getInstallTime() { |
| return mInstallTime; |
| } |
| |
| /** |
| * Returns join key that should be matched with trigger's join key at the time of generating |
| * reports. |
| */ |
| @Nullable |
| public String getDebugJoinKey() { |
| return mDebugJoinKey; |
| } |
| |
| /** |
| * Returns actual platform AdID from getAdId() on app source registration, to be matched with a |
| * web trigger's {@link Trigger#getDebugAdId()} value at the time of generating reports. |
| */ |
| @Nullable |
| public String getPlatformAdId() { |
| return mPlatformAdId; |
| } |
| |
| /** |
| * Returns SHA256 hash of AdID from registration response on web registration concatenated with |
| * enrollment ID, to be matched with an app trigger's {@link Trigger#getPlatformAdId()} value at |
| * the time of generating reports. |
| */ |
| @Nullable |
| public String getDebugAdId() { |
| return mDebugAdId; |
| } |
| |
| /** |
| * Indicates whether event report for this source should be generated with the destinations |
| * where the conversion occurred or merge app and web destinations. Set to true of both app and |
| * web destination should be merged into the array of event report. |
| */ |
| public boolean getCoarseEventReportDestinations() { |
| return mCoarseEventReportDestinations; |
| } |
| |
| /** Returns registration origin used to register the source */ |
| public Uri getRegistrationOrigin() { |
| return mRegistrationOrigin; |
| } |
| |
| /** Returns trigger specs */ |
| public String getTriggerSpecs() { |
| return mTriggerSpecsString; |
| } |
| |
| /** Returns max bucket increments */ |
| public Integer getMaxEventLevelReports() { |
| return mMaxEventLevelReports; |
| } |
| |
| /** |
| * Returns the RBR provided or default value for max_event_level_reports |
| * |
| * @param sourceType Source's Type |
| * @param maxEventLevelReports RBR parsed value for max_event_level_reports |
| * @param flags Flag values |
| */ |
| @NonNull |
| public static Integer getOrDefaultMaxEventLevelReports( |
| @NonNull SourceType sourceType, |
| @Nullable Integer maxEventLevelReports, |
| @NonNull Flags flags) { |
| if (maxEventLevelReports == null) { |
| maxEventLevelReports = |
| sourceType == Source.SourceType.NAVIGATION |
| ? PrivacyParams.NAVIGATION_SOURCE_MAX_REPORTS |
| : flags.getMeasurementVtcConfigurableMaxEventReportsCount(); |
| } |
| return maxEventLevelReports; |
| } |
| |
| /** Returns event attribution status of current source */ |
| public String getEventAttributionStatus() { |
| return mEventAttributionStatusString; |
| } |
| |
| /** Returns privacy parameters */ |
| public String getPrivacyParameters() { |
| return mPrivacyParametersString; |
| } |
| |
| /** See {@link Source#getAppDestinations()} */ |
| public void setAppDestinations(@Nullable List<Uri> appDestinations) { |
| mAppDestinations = appDestinations; |
| } |
| |
| /** See {@link Source#getWebDestinations()} */ |
| public void setWebDestinations(@Nullable List<Uri> webDestinations) { |
| mWebDestinations = webDestinations; |
| } |
| |
| /** Set app install attribution to the {@link Source}. */ |
| public void setInstallAttributed(boolean isInstallAttributed) { |
| mIsInstallAttributed = isInstallAttributed; |
| } |
| |
| /** |
| * @return if it's a derived source, returns the ID of the source it was created from. If it is |
| * null, it is an original source. |
| */ |
| @Nullable |
| public String getParentId() { |
| return mParentId; |
| } |
| |
| /** |
| * Set the status. |
| */ |
| public void setStatus(@Status int status) { |
| mStatus = status; |
| } |
| |
| /** |
| * Set the aggregate contributions value. |
| */ |
| public void setAggregateContributions(int aggregateContributions) { |
| mAggregateContributions = aggregateContributions; |
| } |
| |
| /** |
| * Generates AggregatableFilterData from aggregate filter string in Source, including an entry |
| * for source type. |
| * |
| * @deprecated use {@link #getFilterData(Trigger)} instead. |
| */ |
| @Deprecated |
| public FilterMap getFilterData() throws JSONException { |
| if (mFilterData != null) { |
| return mFilterData; |
| } |
| |
| if (mFilterDataString == null || mFilterDataString.isEmpty()) { |
| mFilterData = new FilterMap.Builder().build(); |
| } else { |
| mFilterData = |
| new FilterMap.Builder() |
| .buildFilterData(new JSONObject(mFilterDataString)) |
| .build(); |
| } |
| mFilterData |
| .getAttributionFilterMap() |
| .put("source_type", Collections.singletonList(mSourceType.getValue())); |
| return mFilterData; |
| } |
| |
| /** |
| * Generates AggregatableFilterData from aggregate filter string in Source, including entries |
| * for source type and duration from source to trigger. |
| */ |
| public FilterMap getFilterData(@NonNull Trigger trigger) throws JSONException { |
| return new FilterMap.Builder() |
| .buildFilterDataV2(new JSONObject(mFilterDataString)) |
| .addStringListValue( |
| "source_type", Collections.singletonList(mSourceType.getValue())) |
| .addLongValue( |
| FilterMap.LOOKBACK_WINDOW, |
| TimeUnit.MILLISECONDS.toSeconds(trigger.getTriggerTime() - mEventTime)) |
| .build(); |
| } |
| |
| @Nullable |
| public UnsignedLong getSharedDebugKey() { |
| return mSharedDebugKey; |
| } |
| |
| /** Returns true if the source has app destination(s), false otherwise. */ |
| public boolean hasAppDestinations() { |
| return mAppDestinations != null && mAppDestinations.size() > 0; |
| } |
| |
| /** Returns true if the source has web destination(s), false otherwise. */ |
| public boolean hasWebDestinations() { |
| return mWebDestinations != null && mWebDestinations.size() > 0; |
| } |
| |
| private static boolean areEqualNullableDestinations(List<Uri> destinations, |
| List<Uri> otherDestinations) { |
| if (destinations == null && otherDestinations == null) { |
| return true; |
| } else if (destinations == null || otherDestinations == null) { |
| return false; |
| } else { |
| return ImmutableMultiset.copyOf(destinations).equals( |
| ImmutableMultiset.copyOf(otherDestinations)); |
| } |
| } |
| |
| /** Parses the event attribution status string. */ |
| @VisibleForTesting |
| public void parseEventAttributionStatus() throws JSONException { |
| JSONArray eventAttributionStatus = new JSONArray(mEventAttributionStatusString); |
| for (int i = 0; i < eventAttributionStatus.length(); i++) { |
| JSONObject json = eventAttributionStatus.getJSONObject(i); |
| mAttributedTriggers.add(new AttributedTrigger(json)); |
| } |
| } |
| |
| /** Build the attributed triggers list from the raw string */ |
| public void buildAttributedTriggers() throws JSONException { |
| if (mAttributedTriggers == null) { |
| mAttributedTriggers = new ArrayList<>(); |
| if (mEventAttributionStatusString != null && !mEventAttributionStatusString.isEmpty()) { |
| parseEventAttributionStatus(); |
| } |
| } |
| } |
| |
| /** Build the flexible event report API from the raw string */ |
| public void buildFlexibleEventReportApi() throws JSONException { |
| buildAttributedTriggers(); |
| if (mFlexEventReportSpec == null) { |
| mFlexEventReportSpec = |
| new ReportSpec( |
| mTriggerSpecsString, |
| getOrDefaultMaxEventLevelReports( |
| mSourceType, mMaxEventLevelReports, FlagsFactory.getFlags()), |
| this, |
| mPrivacyParametersString); |
| } |
| } |
| |
| /** |
| * Builder for {@link Source}. |
| */ |
| public static final class Builder { |
| private final Source mBuilding; |
| |
| public Builder() { |
| mBuilding = new Source(); |
| } |
| |
| /** |
| * Copy builder. |
| * |
| * @param copyFrom copy from source |
| * @return copied source |
| */ |
| public static Builder from(Source copyFrom) { |
| Builder builder = new Builder(); |
| builder.setId(copyFrom.mId); |
| builder.setRegistrationId(copyFrom.mRegistrationId); |
| builder.setAggregateSource(copyFrom.mAggregateSource); |
| builder.setExpiryTime(copyFrom.mExpiryTime); |
| builder.setAppDestinations(copyFrom.mAppDestinations); |
| builder.setWebDestinations(copyFrom.mWebDestinations); |
| builder.setSharedAggregationKeys(copyFrom.mSharedAggregationKeys); |
| builder.setEventId(copyFrom.mEventId); |
| builder.setRegistrant(copyFrom.mRegistrant); |
| builder.setEventTime(copyFrom.mEventTime); |
| builder.setPublisher(copyFrom.mPublisher); |
| builder.setPublisherType(copyFrom.mPublisherType); |
| builder.setInstallCooldownWindow(copyFrom.mInstallCooldownWindow); |
| builder.setInstallAttributed(copyFrom.mIsInstallAttributed); |
| builder.setInstallAttributionWindow(copyFrom.mInstallAttributionWindow); |
| builder.setSourceType(copyFrom.mSourceType); |
| builder.setAdIdPermission(copyFrom.mAdIdPermission); |
| builder.setAggregateContributions(copyFrom.mAggregateContributions); |
| builder.setArDebugPermission(copyFrom.mArDebugPermission); |
| builder.setAttributionMode(copyFrom.mAttributionMode); |
| builder.setDebugKey(copyFrom.mDebugKey); |
| builder.setEventReportDedupKeys(copyFrom.mEventReportDedupKeys); |
| builder.setAggregateReportDedupKeys(copyFrom.mAggregateReportDedupKeys); |
| builder.setEventReportWindow(copyFrom.mEventReportWindow); |
| builder.setEventReportWindows(copyFrom.mEventReportWindows); |
| builder.setMaxEventLevelReports(copyFrom.mMaxEventLevelReports); |
| builder.setAggregatableReportWindow(copyFrom.mAggregatableReportWindow); |
| builder.setEnrollmentId(copyFrom.mEnrollmentId); |
| builder.setFilterData(copyFrom.mFilterDataString); |
| builder.setSharedFilterDataKeys(copyFrom.mSharedFilterDataKeys); |
| builder.setInstallTime(copyFrom.mInstallTime); |
| builder.setIsDebugReporting(copyFrom.mIsDebugReporting); |
| builder.setPriority(copyFrom.mPriority); |
| builder.setStatus(copyFrom.mStatus); |
| builder.setDebugJoinKey(copyFrom.mDebugJoinKey); |
| builder.setPlatformAdId(copyFrom.mPlatformAdId); |
| builder.setDebugAdId(copyFrom.mDebugAdId); |
| builder.setRegistrationOrigin(copyFrom.mRegistrationOrigin); |
| builder.setAttributedTriggers(copyFrom.mAttributedTriggers); |
| builder.setFlexEventReportSpec(copyFrom.mFlexEventReportSpec); |
| builder.setCoarseEventReportDestinations(copyFrom.mCoarseEventReportDestinations); |
| builder.setSharedDebugKey(copyFrom.mSharedDebugKey); |
| return builder; |
| } |
| |
| /** See {@link Source#getId()}. */ |
| @NonNull |
| public Builder setId(@NonNull String id) { |
| mBuilding.mId = id; |
| return this; |
| } |
| |
| /** See {@link Source#getEventId()}. */ |
| @NonNull |
| public Builder setEventId(UnsignedLong eventId) { |
| mBuilding.mEventId = eventId; |
| return this; |
| } |
| |
| /** See {@link Source#getPublisher()}. */ |
| @NonNull |
| public Builder setPublisher(@NonNull Uri publisher) { |
| Validation.validateUri(publisher); |
| mBuilding.mPublisher = publisher; |
| return this; |
| } |
| |
| /** See {@link Source#getPublisherType()}. */ |
| @NonNull |
| public Builder setPublisherType(@EventSurfaceType int publisherType) { |
| mBuilding.mPublisherType = publisherType; |
| return this; |
| } |
| |
| /** See {@link Source#getAppDestinations()}. */ |
| @NonNull |
| public Builder setAppDestinations(@Nullable List<Uri> appDestinations) { |
| Optional.ofNullable(appDestinations).ifPresent(uris -> { |
| Validation.validateNotEmpty(uris); |
| if (uris.size() > 1) { |
| throw new IllegalArgumentException("Received more than one app destination"); |
| } |
| Validation.validateUri(uris.toArray(new Uri[0])); |
| }); |
| mBuilding.mAppDestinations = appDestinations; |
| return this; |
| } |
| |
| /** See {@link Source#getWebDestinations()}. */ |
| @NonNull |
| public Builder setWebDestinations(@Nullable List<Uri> webDestinations) { |
| Optional.ofNullable(webDestinations).ifPresent(uris -> { |
| Validation.validateNotEmpty(uris); |
| Validation.validateUri(uris.toArray(new Uri[0])); |
| }); |
| mBuilding.mWebDestinations = webDestinations; |
| return this; |
| } |
| |
| /** See {@link Source#getEnrollmentId()}. */ |
| @NonNull |
| public Builder setEnrollmentId(@NonNull String enrollmentId) { |
| mBuilding.mEnrollmentId = enrollmentId; |
| return this; |
| } |
| |
| /** See {@link Source#hasAdIdPermission()} */ |
| public Source.Builder setAdIdPermission(boolean adIdPermission) { |
| mBuilding.mAdIdPermission = adIdPermission; |
| return this; |
| } |
| |
| /** See {@link Source#hasArDebugPermission()} */ |
| public Source.Builder setArDebugPermission(boolean arDebugPermission) { |
| mBuilding.mArDebugPermission = arDebugPermission; |
| return this; |
| } |
| |
| /** See {@link Source#getEventId()}. */ |
| @NonNull |
| public Builder setEventTime(long eventTime) { |
| mBuilding.mEventTime = eventTime; |
| return this; |
| } |
| |
| /** |
| * See {@link Source#getExpiryTime()}. |
| */ |
| public Builder setExpiryTime(long expiryTime) { |
| mBuilding.mExpiryTime = expiryTime; |
| return this; |
| } |
| |
| /** See {@link Source#getEventReportWindow()}. */ |
| public Builder setEventReportWindow(Long eventReportWindow) { |
| mBuilding.mEventReportWindow = eventReportWindow; |
| return this; |
| } |
| |
| /** See {@link Source#getEventReportWindows()} ()}. */ |
| public Builder setEventReportWindows(String eventReportWindows) { |
| mBuilding.mEventReportWindows = eventReportWindows; |
| return this; |
| } |
| |
| /** See {@link Source#getAggregatableReportWindow()}. */ |
| public Builder setAggregatableReportWindow(Long aggregateReportWindow) { |
| mBuilding.mAggregatableReportWindow = aggregateReportWindow; |
| return this; |
| } |
| |
| /** See {@link Source#getPriority()}. */ |
| @NonNull |
| public Builder setPriority(long priority) { |
| mBuilding.mPriority = priority; |
| return this; |
| } |
| |
| /** See {@link Source#getDebugKey()}. */ |
| public Builder setDebugKey(@Nullable UnsignedLong debugKey) { |
| mBuilding.mDebugKey = debugKey; |
| return this; |
| } |
| |
| /** See {@link Source#isDebugReporting()}. */ |
| public Builder setIsDebugReporting(boolean isDebugReporting) { |
| mBuilding.mIsDebugReporting = isDebugReporting; |
| return this; |
| } |
| |
| /** See {@link Source#getSourceType()}. */ |
| @NonNull |
| public Builder setSourceType(@NonNull SourceType sourceType) { |
| Validation.validateNonNull(sourceType); |
| mBuilding.mSourceType = sourceType; |
| return this; |
| } |
| |
| /** See {@link Source#getEventReportDedupKeys()}. */ |
| @NonNull |
| public Builder setEventReportDedupKeys(@Nullable List<UnsignedLong> mEventReportDedupKeys) { |
| mBuilding.mEventReportDedupKeys = mEventReportDedupKeys; |
| return this; |
| } |
| |
| /** See {@link Source#getAggregateReportDedupKeys()}. */ |
| @NonNull |
| public Builder setAggregateReportDedupKeys( |
| @NonNull List<UnsignedLong> mAggregateReportDedupKeys) { |
| mBuilding.mAggregateReportDedupKeys = mAggregateReportDedupKeys; |
| return this; |
| } |
| |
| /** See {@link Source#getStatus()}. */ |
| @NonNull |
| public Builder setStatus(@Status int status) { |
| mBuilding.mStatus = status; |
| return this; |
| } |
| |
| /** See {@link Source#getRegistrant()} */ |
| @NonNull |
| public Builder setRegistrant(@NonNull Uri registrant) { |
| Validation.validateUri(registrant); |
| mBuilding.mRegistrant = registrant; |
| return this; |
| } |
| |
| /** See {@link Source#getAttributionMode()} */ |
| @NonNull |
| public Builder setAttributionMode(@AttributionMode int attributionMode) { |
| mBuilding.mAttributionMode = attributionMode; |
| return this; |
| } |
| |
| /** See {@link Source#getInstallAttributionWindow()} */ |
| @NonNull |
| public Builder setInstallAttributionWindow(long installAttributionWindow) { |
| mBuilding.mInstallAttributionWindow = installAttributionWindow; |
| return this; |
| } |
| |
| /** See {@link Source#getInstallCooldownWindow()} */ |
| @NonNull |
| public Builder setInstallCooldownWindow(long installCooldownWindow) { |
| mBuilding.mInstallCooldownWindow = installCooldownWindow; |
| return this; |
| } |
| |
| /** See {@link Source#isInstallAttributed()} */ |
| @NonNull |
| public Builder setInstallAttributed(boolean installAttributed) { |
| mBuilding.mIsInstallAttributed = installAttributed; |
| return this; |
| } |
| |
| /** See {@link Source#getFilterDataString()}. */ |
| public Builder setFilterData(@Nullable String filterMap) { |
| mBuilding.mFilterDataString = filterMap; |
| return this; |
| } |
| |
| /** See {@link Source#getSharedFilterDataKeys()}. */ |
| public Builder setSharedFilterDataKeys(@Nullable String sharedFilterDataKeys) { |
| mBuilding.mSharedFilterDataKeys = sharedFilterDataKeys; |
| return this; |
| } |
| |
| /** See {@link Source#getAggregateSource()} */ |
| @NonNull |
| public Builder setAggregateSource(@Nullable String aggregateSource) { |
| mBuilding.mAggregateSource = aggregateSource; |
| return this; |
| } |
| |
| /** See {@link Source#getAggregateContributions()} */ |
| @NonNull |
| public Builder setAggregateContributions(int aggregateContributions) { |
| mBuilding.mAggregateContributions = aggregateContributions; |
| return this; |
| } |
| |
| /** See {@link Source#getRegistrationId()} */ |
| @NonNull |
| public Builder setRegistrationId(@Nullable String registrationId) { |
| mBuilding.mRegistrationId = registrationId; |
| return this; |
| } |
| |
| /** See {@link Source#getSharedAggregationKeys()} */ |
| @NonNull |
| public Builder setSharedAggregationKeys(@Nullable String sharedAggregationKeys) { |
| mBuilding.mSharedAggregationKeys = sharedAggregationKeys; |
| return this; |
| } |
| |
| /** See {@link Source#getInstallTime()} */ |
| @NonNull |
| public Builder setInstallTime(@Nullable Long installTime) { |
| mBuilding.mInstallTime = installTime; |
| return this; |
| } |
| |
| /** See {@link Source#getParentId()} */ |
| @NonNull |
| public Builder setParentId(@Nullable String parentId) { |
| mBuilding.mParentId = parentId; |
| return this; |
| } |
| |
| /** See {@link Source#getAggregatableAttributionSource()} */ |
| @NonNull |
| public Builder setAggregatableAttributionSource( |
| @Nullable AggregatableAttributionSource aggregatableAttributionSource) { |
| mBuilding.mAggregatableAttributionSource = |
| Optional.ofNullable(aggregatableAttributionSource); |
| return this; |
| } |
| |
| /** See {@link Source#getDebugJoinKey()} */ |
| @NonNull |
| public Builder setDebugJoinKey(@Nullable String debugJoinKey) { |
| mBuilding.mDebugJoinKey = debugJoinKey; |
| return this; |
| } |
| |
| /** See {@link Source#getPlatformAdId()} */ |
| @NonNull |
| public Builder setPlatformAdId(@Nullable String platformAdId) { |
| mBuilding.mPlatformAdId = platformAdId; |
| return this; |
| } |
| |
| /** See {@link Source#getDebugAdId()} */ |
| @NonNull |
| public Builder setDebugAdId(@Nullable String debugAdId) { |
| mBuilding.mDebugAdId = debugAdId; |
| return this; |
| } |
| |
| /** See {@link Source#getRegistrationOrigin()} ()} */ |
| @NonNull |
| public Builder setRegistrationOrigin(Uri registrationOrigin) { |
| mBuilding.mRegistrationOrigin = registrationOrigin; |
| return this; |
| } |
| |
| /** See {@link Source#getAttributedTriggers()} */ |
| @NonNull |
| public Builder setAttributedTriggers(@NonNull List<AttributedTrigger> attributedTriggers) { |
| mBuilding.mAttributedTriggers = attributedTriggers; |
| return this; |
| } |
| |
| /** See {@link Source#getFlexEventReportSpec()} */ |
| @NonNull |
| public Builder setFlexEventReportSpec(@Nullable ReportSpec flexEventReportSpec) { |
| mBuilding.mFlexEventReportSpec = flexEventReportSpec; |
| return this; |
| } |
| |
| /** See {@link Source#getFlexEventReportSpec()} */ |
| @NonNull |
| public Builder buildInitialFlexEventReportSpec(@NonNull Flags flags) throws JSONException { |
| // TODO(b/290100712): Refactor to remove this method |
| if (mBuilding.mTriggerSpecsString == null || mBuilding.mTriggerSpecsString.isEmpty()) { |
| return this; |
| } |
| mBuilding.mFlexEventReportSpec = |
| new ReportSpec( |
| mBuilding.mTriggerSpecsString, |
| getOrDefaultMaxEventLevelReports( |
| mBuilding.mSourceType, mBuilding.mMaxEventLevelReports, flags), |
| null); |
| return this; |
| } |
| |
| /** See {@link Source#getCoarseEventReportDestinations()} */ |
| @NonNull |
| public Builder setCoarseEventReportDestinations(boolean coarseEventReportDestinations) { |
| mBuilding.mCoarseEventReportDestinations = coarseEventReportDestinations; |
| return this; |
| } |
| |
| /** See {@link Source#getTriggerSpecs()} */ |
| @NonNull |
| public Builder setTriggerSpecs(@Nullable String triggerSpecs) { |
| mBuilding.mTriggerSpecsString = triggerSpecs; |
| return this; |
| } |
| |
| /** See {@link Source#getMaxEventLevelReports()} */ |
| @NonNull |
| public Builder setMaxEventLevelReports(@Nullable Integer maxEventLevelReports) { |
| mBuilding.mMaxEventLevelReports = maxEventLevelReports; |
| return this; |
| } |
| |
| /** See {@link Source#getEventAttributionStatus()} */ |
| @NonNull |
| public Builder setEventAttributionStatus(@Nullable String eventAttributionStatus) { |
| mBuilding.mEventAttributionStatusString = eventAttributionStatus; |
| return this; |
| } |
| |
| /** See {@link Source#getPrivacyParameters()} */ |
| @NonNull |
| public Builder setPrivacyParameters(@Nullable String privacyParameters) { |
| mBuilding.mPrivacyParametersString = privacyParameters; |
| return this; |
| } |
| |
| /** See {@link Source#getSharedDebugKey()}. */ |
| @NonNull |
| public Builder setSharedDebugKey(@Nullable UnsignedLong sharedDebugKey) { |
| mBuilding.mSharedDebugKey = sharedDebugKey; |
| return this; |
| } |
| |
| /** Build the {@link Source}. */ |
| @NonNull |
| public Source build() { |
| Validation.validateNonNull( |
| mBuilding.mPublisher, |
| mBuilding.mEnrollmentId, |
| mBuilding.mRegistrant, |
| mBuilding.mSourceType, |
| mBuilding.mAggregateReportDedupKeys, |
| mBuilding.mEventReportDedupKeys, |
| mBuilding.mRegistrationOrigin); |
| |
| return mBuilding; |
| } |
| } |
| } |