1 /* 2 * Copyright 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.app.appsearch.safeparcel; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SuppressLint; 22 import android.app.appsearch.EmbeddingVector; 23 import android.app.appsearch.annotation.CanIgnoreReturnValue; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 27 import java.util.Arrays; 28 import java.util.Objects; 29 30 /** 31 * A {@link SafeParcelable} to hold the value of a property in {@code GenericDocument#mProperties}. 32 * 33 * <p>This resembles PropertyProto in IcingLib. 34 * 35 * @hide 36 */ 37 @SafeParcelable.Class(creator = "PropertyParcelCreator") 38 // This won't be used to send data over binder, and we have to use Parcelable for code sync purpose. 39 @SuppressLint("BanParcelableUsage") 40 public final class PropertyParcel extends AbstractSafeParcelable implements Parcelable { 41 @NonNull 42 public static final Parcelable.Creator<PropertyParcel> CREATOR = new PropertyParcelCreator(); 43 44 @NonNull 45 @Field(id = 1, getter = "getPropertyName") 46 private final String mPropertyName; 47 48 @Nullable 49 @Field(id = 2, getter = "getStringValues") 50 private final String[] mStringValues; 51 52 @Nullable 53 @Field(id = 3, getter = "getLongValues") 54 private final long[] mLongValues; 55 56 @Nullable 57 @Field(id = 4, getter = "getDoubleValues") 58 private final double[] mDoubleValues; 59 60 @Nullable 61 @Field(id = 5, getter = "getBooleanValues") 62 private final boolean[] mBooleanValues; 63 64 @Nullable 65 @Field(id = 6, getter = "getBytesValues") 66 private final byte[][] mBytesValues; 67 68 @Nullable 69 @Field(id = 7, getter = "getDocumentValues") 70 private final GenericDocumentParcel[] mDocumentValues; 71 72 @Nullable 73 @Field(id = 8, getter = "getEmbeddingValues") 74 private final EmbeddingVector[] mEmbeddingValues; 75 76 @Nullable private Integer mHashCode; 77 78 @Constructor PropertyParcel( @aramid = 1) @onNull String propertyName, @Param(id = 2) @Nullable String[] stringValues, @Param(id = 3) @Nullable long[] longValues, @Param(id = 4) @Nullable double[] doubleValues, @Param(id = 5) @Nullable boolean[] booleanValues, @Param(id = 6) @Nullable byte[][] bytesValues, @Param(id = 7) @Nullable GenericDocumentParcel[] documentValues, @Param(id = 8) @Nullable EmbeddingVector[] embeddingValues)79 PropertyParcel( 80 @Param(id = 1) @NonNull String propertyName, 81 @Param(id = 2) @Nullable String[] stringValues, 82 @Param(id = 3) @Nullable long[] longValues, 83 @Param(id = 4) @Nullable double[] doubleValues, 84 @Param(id = 5) @Nullable boolean[] booleanValues, 85 @Param(id = 6) @Nullable byte[][] bytesValues, 86 @Param(id = 7) @Nullable GenericDocumentParcel[] documentValues, 87 @Param(id = 8) @Nullable EmbeddingVector[] embeddingValues) { 88 mPropertyName = Objects.requireNonNull(propertyName); 89 mStringValues = stringValues; 90 mLongValues = longValues; 91 mDoubleValues = doubleValues; 92 mBooleanValues = booleanValues; 93 mBytesValues = bytesValues; 94 mDocumentValues = documentValues; 95 mEmbeddingValues = embeddingValues; 96 checkOnlyOneArrayCanBeSet(); 97 } 98 99 /** Returns the name of the property. */ 100 @NonNull getPropertyName()101 public String getPropertyName() { 102 return mPropertyName; 103 } 104 105 /** Returns {@code String} values in an array. */ 106 @Nullable getStringValues()107 public String[] getStringValues() { 108 return mStringValues; 109 } 110 111 /** Returns {@code long} values in an array. */ 112 @Nullable getLongValues()113 public long[] getLongValues() { 114 return mLongValues; 115 } 116 117 /** Returns {@code double} values in an array. */ 118 @Nullable getDoubleValues()119 public double[] getDoubleValues() { 120 return mDoubleValues; 121 } 122 123 /** Returns {@code boolean} values in an array. */ 124 @Nullable getBooleanValues()125 public boolean[] getBooleanValues() { 126 return mBooleanValues; 127 } 128 129 /** Returns a two-dimension {@code byte} array. */ 130 @Nullable getBytesValues()131 public byte[][] getBytesValues() { 132 return mBytesValues; 133 } 134 135 /** Returns {@link GenericDocumentParcel}s in an array. */ 136 @Nullable getDocumentValues()137 public GenericDocumentParcel[] getDocumentValues() { 138 return mDocumentValues; 139 } 140 141 /** Returns {@link EmbeddingVector}s in an array. */ 142 @Nullable getEmbeddingValues()143 public EmbeddingVector[] getEmbeddingValues() { 144 return mEmbeddingValues; 145 } 146 147 /** 148 * Returns the held values in an array for this property. 149 * 150 * <p>Different from other getter methods, this one will return an {@link Object}. 151 */ 152 @Nullable getValues()153 public Object getValues() { 154 if (mStringValues != null) { 155 return mStringValues; 156 } 157 if (mLongValues != null) { 158 return mLongValues; 159 } 160 if (mDoubleValues != null) { 161 return mDoubleValues; 162 } 163 if (mBooleanValues != null) { 164 return mBooleanValues; 165 } 166 if (mBytesValues != null) { 167 return mBytesValues; 168 } 169 if (mDocumentValues != null) { 170 return mDocumentValues; 171 } 172 if (mEmbeddingValues != null) { 173 return mEmbeddingValues; 174 } 175 return null; 176 } 177 178 /** 179 * Checks there is one and only one array can be set for the property. 180 * 181 * @throws IllegalArgumentException if 0, or more than 1 arrays are set. 182 */ checkOnlyOneArrayCanBeSet()183 private void checkOnlyOneArrayCanBeSet() { 184 int notNullCount = 0; 185 if (mStringValues != null) { 186 ++notNullCount; 187 } 188 if (mLongValues != null) { 189 ++notNullCount; 190 } 191 if (mDoubleValues != null) { 192 ++notNullCount; 193 } 194 if (mBooleanValues != null) { 195 ++notNullCount; 196 } 197 if (mBytesValues != null) { 198 ++notNullCount; 199 } 200 if (mDocumentValues != null) { 201 ++notNullCount; 202 } 203 if (mEmbeddingValues != null) { 204 ++notNullCount; 205 } 206 if (notNullCount == 0 || notNullCount > 1) { 207 throw new IllegalArgumentException( 208 "One and only one type array can be set in PropertyParcel"); 209 } 210 } 211 212 @Override hashCode()213 public int hashCode() { 214 if (mHashCode == null) { 215 int hashCode = 0; 216 if (mStringValues != null) { 217 hashCode = Arrays.hashCode(mStringValues); 218 } else if (mLongValues != null) { 219 hashCode = Arrays.hashCode(mLongValues); 220 } else if (mDoubleValues != null) { 221 hashCode = Arrays.hashCode(mDoubleValues); 222 } else if (mBooleanValues != null) { 223 hashCode = Arrays.hashCode(mBooleanValues); 224 } else if (mBytesValues != null) { 225 hashCode = Arrays.deepHashCode(mBytesValues); 226 } else if (mDocumentValues != null) { 227 hashCode = Arrays.hashCode(mDocumentValues); 228 } else if (mEmbeddingValues != null) { 229 hashCode = Arrays.deepHashCode(mEmbeddingValues); 230 } 231 mHashCode = Objects.hash(mPropertyName, hashCode); 232 } 233 return mHashCode; 234 } 235 236 @Override equals(@ullable Object other)237 public boolean equals(@Nullable Object other) { 238 if (this == other) { 239 return true; 240 } 241 if (!(other instanceof PropertyParcel)) { 242 return false; 243 } 244 PropertyParcel otherPropertyParcel = (PropertyParcel) other; 245 if (!mPropertyName.equals(otherPropertyParcel.mPropertyName)) { 246 return false; 247 } 248 return Arrays.equals(mStringValues, otherPropertyParcel.mStringValues) 249 && Arrays.equals(mLongValues, otherPropertyParcel.mLongValues) 250 && Arrays.equals(mDoubleValues, otherPropertyParcel.mDoubleValues) 251 && Arrays.equals(mBooleanValues, otherPropertyParcel.mBooleanValues) 252 && Arrays.deepEquals(mBytesValues, otherPropertyParcel.mBytesValues) 253 && Arrays.equals(mDocumentValues, otherPropertyParcel.mDocumentValues) 254 && Arrays.deepEquals(mEmbeddingValues, otherPropertyParcel.mEmbeddingValues); 255 } 256 257 @Override writeToParcel(@onNull Parcel dest, int flags)258 public void writeToParcel(@NonNull Parcel dest, int flags) { 259 PropertyParcelCreator.writeToParcel(this, dest, flags); 260 } 261 262 /** Builder for {@link PropertyParcel}. */ 263 public static final class Builder { 264 private String mPropertyName; 265 private String[] mStringValues; 266 private long[] mLongValues; 267 private double[] mDoubleValues; 268 private boolean[] mBooleanValues; 269 private byte[][] mBytesValues; 270 private GenericDocumentParcel[] mDocumentValues; 271 private EmbeddingVector[] mEmbeddingValues; 272 Builder(@onNull String propertyName)273 public Builder(@NonNull String propertyName) { 274 mPropertyName = Objects.requireNonNull(propertyName); 275 } 276 277 /** Sets String values. */ 278 @CanIgnoreReturnValue 279 @NonNull setStringValues(@onNull String[] stringValues)280 public Builder setStringValues(@NonNull String[] stringValues) { 281 mStringValues = Objects.requireNonNull(stringValues); 282 return this; 283 } 284 285 /** Sets long values. */ 286 @CanIgnoreReturnValue 287 @NonNull setLongValues(@onNull long[] longValues)288 public Builder setLongValues(@NonNull long[] longValues) { 289 mLongValues = Objects.requireNonNull(longValues); 290 return this; 291 } 292 293 /** Sets double values. */ 294 @CanIgnoreReturnValue 295 @NonNull setDoubleValues(@onNull double[] doubleValues)296 public Builder setDoubleValues(@NonNull double[] doubleValues) { 297 mDoubleValues = Objects.requireNonNull(doubleValues); 298 return this; 299 } 300 301 /** Sets boolean values. */ 302 @CanIgnoreReturnValue 303 @NonNull setBooleanValues(@onNull boolean[] booleanValues)304 public Builder setBooleanValues(@NonNull boolean[] booleanValues) { 305 mBooleanValues = Objects.requireNonNull(booleanValues); 306 return this; 307 } 308 309 /** Sets a two dimension byte array. */ 310 @CanIgnoreReturnValue 311 @NonNull setBytesValues(@onNull byte[][] bytesValues)312 public Builder setBytesValues(@NonNull byte[][] bytesValues) { 313 mBytesValues = Objects.requireNonNull(bytesValues); 314 return this; 315 } 316 317 /** Sets document values. */ 318 @CanIgnoreReturnValue 319 @NonNull setDocumentValues(@onNull GenericDocumentParcel[] documentValues)320 public Builder setDocumentValues(@NonNull GenericDocumentParcel[] documentValues) { 321 mDocumentValues = Objects.requireNonNull(documentValues); 322 return this; 323 } 324 325 /** Sets embedding values. */ 326 @CanIgnoreReturnValue 327 @NonNull setEmbeddingValues(@onNull EmbeddingVector[] embeddingValues)328 public Builder setEmbeddingValues(@NonNull EmbeddingVector[] embeddingValues) { 329 mEmbeddingValues = Objects.requireNonNull(embeddingValues); 330 return this; 331 } 332 333 /** Builds a {@link PropertyParcel}. */ 334 @NonNull build()335 public PropertyParcel build() { 336 return new PropertyParcel( 337 mPropertyName, 338 mStringValues, 339 mLongValues, 340 mDoubleValues, 341 mBooleanValues, 342 mBytesValues, 343 mDocumentValues, 344 mEmbeddingValues); 345 } 346 } 347 } 348