1 /* 2 * Copyright (C) 2023 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.measurement; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.net.Uri; 22 import android.os.Build; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.view.InputEvent; 26 27 import com.android.adservices.AdServicesParcelableUtil; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Objects; 32 33 /** 34 * Class to hold input to measurement source registration calls. 35 */ 36 public final class SourceRegistrationRequest implements Parcelable { 37 private static final int REGISTRATION_URIS_MAX_COUNT = 20; 38 /** Registration URIs to fetch sources. */ 39 @NonNull private final List<Uri> mRegistrationUris; 40 41 /** 42 * User Interaction {@link InputEvent} used by the AttributionReporting API to distinguish 43 * clicks from views. It will be an {@link InputEvent} object (for a click event) or null (for a 44 * view event). 45 */ 46 @Nullable private final InputEvent mInputEvent; 47 SourceRegistrationRequest(@onNull Builder builder)48 private SourceRegistrationRequest(@NonNull Builder builder) { 49 mRegistrationUris = builder.mRegistrationUris; 50 mInputEvent = builder.mInputEvent; 51 } 52 SourceRegistrationRequest(@onNull Parcel in)53 private SourceRegistrationRequest(@NonNull Parcel in) { 54 Objects.requireNonNull(in); 55 List<Uri> registrationsUris = new ArrayList<>(); 56 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { 57 in.readList(registrationsUris, Uri.class.getClassLoader()); 58 } else { 59 in.readList(registrationsUris, Uri.class.getClassLoader(), Uri.class); 60 } 61 mRegistrationUris = registrationsUris; 62 mInputEvent = 63 AdServicesParcelableUtil.readNullableFromParcel( 64 in, InputEvent.CREATOR::createFromParcel); 65 } 66 67 @Override equals(Object o)68 public boolean equals(Object o) { 69 if (this == o) return true; 70 if (!(o instanceof SourceRegistrationRequest)) return false; 71 SourceRegistrationRequest that = (SourceRegistrationRequest) o; 72 return Objects.equals(mRegistrationUris, that.mRegistrationUris) 73 && Objects.equals(mInputEvent, that.mInputEvent); 74 } 75 76 @Override hashCode()77 public int hashCode() { 78 return Objects.hash(mRegistrationUris, mInputEvent); 79 } 80 81 /** Registration URIs to fetch sources. */ 82 @NonNull getRegistrationUris()83 public List<Uri> getRegistrationUris() { 84 return mRegistrationUris; 85 } 86 87 /** 88 * User Interaction {@link InputEvent} used by the AttributionReporting API to distinguish 89 * clicks from views. It will be an {@link InputEvent} object (for a click event) or null (for a 90 * view event) 91 */ 92 @Nullable getInputEvent()93 public InputEvent getInputEvent() { 94 return mInputEvent; 95 } 96 97 @Override describeContents()98 public int describeContents() { 99 return 0; 100 } 101 102 @Override writeToParcel(@onNull Parcel out, int flags)103 public void writeToParcel(@NonNull Parcel out, int flags) { 104 Objects.requireNonNull(out); 105 out.writeList(mRegistrationUris); 106 AdServicesParcelableUtil.writeNullableToParcel( 107 out, mInputEvent, (target, event) -> event.writeToParcel(target, flags)); 108 } 109 110 /** Builder for {@link SourceRegistrationRequest}. */ 111 public static final class Builder { 112 /** Registration {@link Uri}s to fetch sources. */ 113 @NonNull private final List<Uri> mRegistrationUris; 114 /** 115 * User Interaction InputEvent used by the attribution reporting API to distinguish clicks 116 * from views. 117 */ 118 @Nullable private InputEvent mInputEvent; 119 120 /** 121 * Builder constructor for {@link SourceRegistrationRequest}. 122 * 123 * @param registrationUris source registration {@link Uri}s 124 * @throws IllegalArgumentException if the scheme for one or more of the 125 * {@code registrationUris} is not HTTPS 126 */ Builder(@onNull List<Uri> registrationUris)127 public Builder(@NonNull List<Uri> registrationUris) { 128 Objects.requireNonNull(registrationUris); 129 if (registrationUris.isEmpty() 130 || registrationUris.size() > REGISTRATION_URIS_MAX_COUNT) { 131 throw new IllegalArgumentException( 132 String.format( 133 "Requests should have at least 1 and at most %d URIs." 134 + " Request has %d URIs.", 135 REGISTRATION_URIS_MAX_COUNT, registrationUris.size())); 136 } 137 for (Uri registrationUri : registrationUris) { 138 if (registrationUri.getScheme() == null 139 || !registrationUri.getScheme().equalsIgnoreCase("https")) { 140 throw new IllegalArgumentException( 141 "registrationUri must have an HTTPS scheme"); 142 } 143 } 144 mRegistrationUris = registrationUris; 145 } 146 147 /** 148 * Setter corresponding to {@link #getInputEvent()}. 149 * 150 * @param inputEvent User Interaction {@link InputEvent} used by the AttributionReporting 151 * API to distinguish clicks from views. It will be an {@link InputEvent} object (for a 152 * click event) or null (for a view event) 153 * @return builder 154 */ 155 @NonNull setInputEvent(@ullable InputEvent inputEvent)156 public Builder setInputEvent(@Nullable InputEvent inputEvent) { 157 mInputEvent = inputEvent; 158 return this; 159 } 160 161 /** Pre-validates parameters and builds {@link SourceRegistrationRequest}. */ 162 @NonNull build()163 public SourceRegistrationRequest build() { 164 return new SourceRegistrationRequest(this); 165 } 166 } 167 168 /** Creator for Paracelable (via reflection). */ 169 @NonNull 170 public static final Parcelable.Creator<SourceRegistrationRequest> CREATOR = 171 new Parcelable.Creator<>() { 172 @Override 173 public SourceRegistrationRequest createFromParcel(Parcel in) { 174 return new SourceRegistrationRequest(in); 175 } 176 177 @Override 178 public SourceRegistrationRequest[] newArray(int size) { 179 return new SourceRegistrationRequest[size]; 180 } 181 }; 182 } 183