diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java index 4378a9811f124..c1fcd6c9aca9d 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java @@ -120,7 +120,7 @@ public final class AppSearchSchema { /** Builder for {@link AppSearchSchema objects}. */ public static final class Builder { private final String mSchemaType; - private final ArrayList mPropertyBundles = new ArrayList<>(); + private ArrayList mPropertyBundles = new ArrayList<>(); private final Set mPropertyNames = new ArraySet<>(); private boolean mBuilt = false; @@ -133,8 +133,8 @@ public final class AppSearchSchema { /** Adds a property to the given type. */ @NonNull public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(propertyConfig); + resetIfBuilt(); String name = propertyConfig.getName(); if (!mPropertyNames.add(name)) { throw new IllegalSchemaException("Property defined more than once: " + name); @@ -143,20 +143,22 @@ public final class AppSearchSchema { return this; } - /** - * Constructs a new {@link AppSearchSchema} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - */ + /** Constructs a new {@link AppSearchSchema} from the contents of this builder. */ @NonNull public AppSearchSchema build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Bundle bundle = new Bundle(); bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mSchemaType); bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles); mBuilt = true; return new AppSearchSchema(bundle); } + + private void resetIfBuilt() { + if (mBuilt) { + mPropertyBundles = new ArrayList<>(mPropertyBundles); + mBuilt = false; + } + } } /** @@ -251,6 +253,7 @@ public final class AppSearchSchema { } @Override + @NonNull public String toString() { return mBundle.toString(); } @@ -410,16 +413,14 @@ public final class AppSearchSchema { /** Builder for {@link StringPropertyConfig}. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyName; + private @Cardinality int mCardinality = CARDINALITY_OPTIONAL; + private @IndexingType int mIndexingType = INDEXING_TYPE_NONE; + private @TokenizerType int mTokenizerType = TOKENIZER_TYPE_NONE; /** Creates a new {@link StringPropertyConfig.Builder}. */ public Builder(@NonNull String propertyName) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); - mBundle.putInt(INDEXING_TYPE_FIELD, INDEXING_TYPE_NONE); - mBundle.putInt(TOKENIZER_TYPE_FIELD, TOKENIZER_TYPE_NONE); + mPropertyName = Objects.requireNonNull(propertyName); } /** @@ -431,10 +432,9 @@ public final class AppSearchSchema { @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass @NonNull public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality"); - mBundle.putInt(CARDINALITY_FIELD, cardinality); + mCardinality = cardinality; return this; } @@ -446,10 +446,9 @@ public final class AppSearchSchema { */ @NonNull public StringPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType"); - mBundle.putInt(INDEXING_TYPE_FIELD, indexingType); + mIndexingType = indexingType; return this; } @@ -466,25 +465,22 @@ public final class AppSearchSchema { */ @NonNull public StringPropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType"); - mBundle.putInt(TOKENIZER_TYPE_FIELD, tokenizerType); + mTokenizerType = tokenizerType; return this; } - /** - * Constructs a new {@link StringPropertyConfig} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link StringPropertyConfig} from the contents of this builder. */ @NonNull public StringPropertyConfig build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new StringPropertyConfig(mBundle); + Bundle bundle = new Bundle(); + bundle.putString(NAME_FIELD, mPropertyName); + bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING); + bundle.putInt(CARDINALITY_FIELD, mCardinality); + bundle.putInt(INDEXING_TYPE_FIELD, mIndexingType); + bundle.putInt(TOKENIZER_TYPE_FIELD, mTokenizerType); + return new StringPropertyConfig(bundle); } } } @@ -497,14 +493,12 @@ public final class AppSearchSchema { /** Builder for {@link Int64PropertyConfig}. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyName; + private @Cardinality int mCardinality = CARDINALITY_OPTIONAL; /** Creates a new {@link Int64PropertyConfig.Builder}. */ public Builder(@NonNull String propertyName) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); + mPropertyName = Objects.requireNonNull(propertyName); } /** @@ -516,25 +510,20 @@ public final class AppSearchSchema { @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass @NonNull public Int64PropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality"); - mBundle.putInt(CARDINALITY_FIELD, cardinality); + mCardinality = cardinality; return this; } - /** - * Constructs a new {@link Int64PropertyConfig} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link Int64PropertyConfig} from the contents of this builder. */ @NonNull public Int64PropertyConfig build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new Int64PropertyConfig(mBundle); + Bundle bundle = new Bundle(); + bundle.putString(NAME_FIELD, mPropertyName); + bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64); + bundle.putInt(CARDINALITY_FIELD, mCardinality); + return new Int64PropertyConfig(bundle); } } } @@ -547,14 +536,12 @@ public final class AppSearchSchema { /** Builder for {@link DoublePropertyConfig}. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyName; + private @Cardinality int mCardinality = CARDINALITY_OPTIONAL; /** Creates a new {@link DoublePropertyConfig.Builder}. */ public Builder(@NonNull String propertyName) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); + mPropertyName = Objects.requireNonNull(propertyName); } /** @@ -566,25 +553,20 @@ public final class AppSearchSchema { @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass @NonNull public DoublePropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality"); - mBundle.putInt(CARDINALITY_FIELD, cardinality); + mCardinality = cardinality; return this; } - /** - * Constructs a new {@link DoublePropertyConfig} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link DoublePropertyConfig} from the contents of this builder. */ @NonNull public DoublePropertyConfig build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new DoublePropertyConfig(mBundle); + Bundle bundle = new Bundle(); + bundle.putString(NAME_FIELD, mPropertyName); + bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE); + bundle.putInt(CARDINALITY_FIELD, mCardinality); + return new DoublePropertyConfig(bundle); } } } @@ -597,14 +579,12 @@ public final class AppSearchSchema { /** Builder for {@link BooleanPropertyConfig}. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyName; + private @Cardinality int mCardinality = CARDINALITY_OPTIONAL; /** Creates a new {@link BooleanPropertyConfig.Builder}. */ public Builder(@NonNull String propertyName) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); + mPropertyName = Objects.requireNonNull(propertyName); } /** @@ -616,25 +596,20 @@ public final class AppSearchSchema { @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass @NonNull public BooleanPropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality"); - mBundle.putInt(CARDINALITY_FIELD, cardinality); + mCardinality = cardinality; return this; } - /** - * Constructs a new {@link BooleanPropertyConfig} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link BooleanPropertyConfig} from the contents of this builder. */ @NonNull public BooleanPropertyConfig build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new BooleanPropertyConfig(mBundle); + Bundle bundle = new Bundle(); + bundle.putString(NAME_FIELD, mPropertyName); + bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN); + bundle.putInt(CARDINALITY_FIELD, mCardinality); + return new BooleanPropertyConfig(bundle); } } } @@ -647,14 +622,12 @@ public final class AppSearchSchema { /** Builder for {@link BytesPropertyConfig}. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyName; + private @Cardinality int mCardinality = CARDINALITY_OPTIONAL; /** Creates a new {@link BytesPropertyConfig.Builder}. */ public Builder(@NonNull String propertyName) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); + mPropertyName = Objects.requireNonNull(propertyName); } /** @@ -666,25 +639,20 @@ public final class AppSearchSchema { @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass @NonNull public BytesPropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality"); - mBundle.putInt(CARDINALITY_FIELD, cardinality); + mCardinality = cardinality; return this; } - /** - * Constructs a new {@link BytesPropertyConfig} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link BytesPropertyConfig} from the contents of this builder. */ @NonNull public BytesPropertyConfig build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new BytesPropertyConfig(mBundle); + Bundle bundle = new Bundle(); + bundle.putString(NAME_FIELD, mPropertyName); + bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES); + bundle.putInt(CARDINALITY_FIELD, mCardinality); + return new BytesPropertyConfig(bundle); } } } @@ -715,20 +683,13 @@ public final class AppSearchSchema { return mBundle.getBoolean(INDEX_NESTED_PROPERTIES_FIELD); } - /** - * Builder for {@link DocumentPropertyConfig}. - * - *

The following properties must be set, or {@link DocumentPropertyConfig} construction - * will fail: - * - *

    - *
  • cardinality - *
  • schemaType - *
- */ + /** Builder for {@link DocumentPropertyConfig}. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyName; + // TODO(b/181887768): This should be final + private String mSchemaType; + private @Cardinality int mCardinality = CARDINALITY_OPTIONAL; + private boolean mShouldIndexNestedProperties = false; /** * Creates a new {@link DocumentPropertyConfig.Builder}. @@ -740,11 +701,8 @@ public final class AppSearchSchema { * Documents of different types cannot be mixed into a single property. */ public Builder(@NonNull String propertyName, @NonNull String schemaType) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); - mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, false); - mBundle.putString(SCHEMA_TYPE_FIELD, schemaType); + mPropertyName = Objects.requireNonNull(propertyName); + mSchemaType = Objects.requireNonNull(schemaType); } /** @@ -754,10 +712,8 @@ public final class AppSearchSchema { @Deprecated @UnsupportedAppUsage public Builder(@NonNull String propertyName) { - mBundle.putString(NAME_FIELD, propertyName); - mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT); - mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL); - mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, false); + mPropertyName = Objects.requireNonNull(propertyName); + mSchemaType = null; } /** @@ -768,7 +724,7 @@ public final class AppSearchSchema { @UnsupportedAppUsage @NonNull public Builder setSchemaType(@NonNull String schemaType) { - mBundle.putString(SCHEMA_TYPE_FIELD, schemaType); + mSchemaType = Objects.requireNonNull(schemaType); return this; } @@ -781,10 +737,9 @@ public final class AppSearchSchema { @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass @NonNull public DocumentPropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality"); - mBundle.putInt(CARDINALITY_FIELD, cardinality); + mCardinality = cardinality; return this; } @@ -798,8 +753,7 @@ public final class AppSearchSchema { @NonNull public DocumentPropertyConfig.Builder setShouldIndexNestedProperties( boolean indexNestedProperties) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, indexNestedProperties); + mShouldIndexNestedProperties = indexNestedProperties; return this; } @@ -815,19 +769,18 @@ public final class AppSearchSchema { return setShouldIndexNestedProperties(indexNestedProperties); } - /** - * Constructs a new {@link PropertyConfig} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - * - * @throws IllegalStateException if the builder has already been used (e.g. missing - * {@code dataType}). - */ + /** Constructs a new {@link PropertyConfig} from the contents of this builder. */ @NonNull public DocumentPropertyConfig build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new DocumentPropertyConfig(mBundle); + Bundle bundle = new Bundle(); + bundle.putString(NAME_FIELD, mPropertyName); + bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT); + bundle.putInt(CARDINALITY_FIELD, mCardinality); + bundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, mShouldIndexNestedProperties); + // TODO(b/181887768): Remove checkNotNull after the deprecated constructor (which + // is the only way to get null here) is removed + bundle.putString(SCHEMA_TYPE_FIELD, Objects.requireNonNull(mSchemaType)); + return new DocumentPropertyConfig(bundle); } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java index 39a48847d1c23..736deab429e39 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java @@ -892,64 +892,129 @@ public class GenericDocument { @Override @NonNull public String toString() { - return bundleToString(mBundle).toString(); + return formatGenericDocumentString(this, /*indentLevel=*/ 0); } - private static StringBuilder bundleToString(Bundle bundle) { + @NonNull + private static String formatGenericDocumentString( + @NonNull GenericDocument document, int indentLevel) { StringBuilder stringBuilder = new StringBuilder(); - try { - String[] names = bundle.keySet().toArray(new String[0]); - // Sort names to make output deterministic. We need a custom comparator to handle - // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is - // only available since N). - Arrays.sort( - names, - (@Nullable String s1, @Nullable String s2) -> { - if (s1 == null) { - return s2 == null ? 0 : -1; - } else if (s2 == null) { - return 1; - } else { - return s1.compareTo(s2); - } - }); - for (String name : names) { - stringBuilder.append("{ name: '").append(name).append("' value: "); - Object valueObject = bundle.get(name); - if (valueObject == null) { - stringBuilder.append(""); - } else if (valueObject instanceof Bundle) { - stringBuilder.append(bundleToString((Bundle) valueObject)); - } else if (valueObject.getClass().isArray()) { - stringBuilder.append("[ "); - for (int i = 0; i < Array.getLength(valueObject); i++) { - Object element = Array.get(valueObject, i); - stringBuilder.append("'"); - if (element instanceof Bundle) { - stringBuilder.append(bundleToString((Bundle) element)); - } else { - stringBuilder.append(Array.get(valueObject, i)); - } - stringBuilder.append("' "); - } - stringBuilder.append("]"); - } else if (valueObject instanceof List) { - @SuppressWarnings("unchecked") - List bundles = (List) valueObject; - for (int i = 0; i < bundles.size(); i++) { - stringBuilder.append(bundleToString(bundles.get(i))); - } - } else { - stringBuilder.append(valueObject.toString()); - } - stringBuilder.append(" } "); + stringBuilder.append(getIndent(indentLevel)).append("{\n"); + + String indentLevelOneString = getIndent(indentLevel + 1); + + stringBuilder + .append(indentLevelOneString) + .append("namespace: \"") + .append(document.getNamespace()) + .append("\",\n"); + + stringBuilder + .append(indentLevelOneString) + .append("id: \"") + .append(document.getId()) + .append("\",\n"); + + stringBuilder + .append(indentLevelOneString) + .append("score: " + document.getScore()) + .append(",\n"); + + stringBuilder + .append(indentLevelOneString) + .append("schemaType: \"") + .append(document.getSchemaType()) + .append("\",\n"); + + stringBuilder + .append(indentLevelOneString) + .append("creationTimestampMillis: " + document.getCreationTimestampMillis()) + .append(",\n"); + + stringBuilder + .append(indentLevelOneString) + .append("timeToLiveMillis: " + document.getTtlMillis()) + .append(",\n"); + + stringBuilder.append(indentLevelOneString).append("properties: {\n"); + + int idx = 0; + for (String propertyName : document.getPropertyNames()) { + Object property = document.getProperty(propertyName); + stringBuilder + .append(getIndent(indentLevel + 2)) + .append("\"") + .append(propertyName) + .append("\"") + .append(": "); + stringBuilder.append(getPropertyString(property, indentLevel + 2)); + if (idx != document.getPropertyNames().size() - 1) { + stringBuilder.append(",\n"); } - } catch (RuntimeException e) { - // Catch any exceptions here since corrupt Bundles can throw different types of - // exceptions (e.g. b/38445840 & b/68937025). - stringBuilder.append(""); + ++idx; } - return stringBuilder; + + stringBuilder.append("\n"); + stringBuilder.append(indentLevelOneString).append("}"); + + stringBuilder.append("\n"); + stringBuilder.append(getIndent(indentLevel)).append("}"); + + return stringBuilder.toString(); + } + + /** + * Creates string for property. + * + * @param property property object to create string for. + * @param indentLevel base indent level for property. + */ + @NonNull + private static String getPropertyString(@NonNull Object property, int indentLevel) { + Objects.requireNonNull(property); + + StringBuilder str = new StringBuilder("["); + + if (property instanceof GenericDocument[]) { + GenericDocument[] documentValues = (GenericDocument[]) property; + for (int i = 0; i < documentValues.length; ++i) { + str.append("\n"); + str.append(formatGenericDocumentString(documentValues[i], indentLevel + 1)); + if (i != documentValues.length - 1) { + str.append(", "); + } + str.append("\n"); + } + str.append(getIndent(indentLevel)); + } else { + int propertyArrLength = Array.getLength(property); + for (int i = 0; i < propertyArrLength; i++) { + Object propertyElement = Array.get(property, i); + if (propertyElement instanceof String) { + str.append("\"").append(propertyElement).append("\""); + } else if (propertyElement instanceof byte[]) { + str.append(Arrays.toString((byte[]) propertyElement)); + } else { + str.append(propertyElement); + } + if (i != propertyArrLength - 1) { + str.append(", "); + } + } + } + + str.append("]"); + return str.toString(); + } + + /** Creates string for given indent level. */ + @NonNull + private static String getIndent(int indentLevel) { + StringBuilder indentedString = new StringBuilder(); + for (int i = 0; i < indentLevel; ++i) { + indentedString.append(" "); + } + return indentedString.toString(); } /** diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java index 58fd8bee8d4a8..e324b9f81d9c2 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java @@ -20,8 +20,6 @@ import android.annotation.NonNull; import android.util.ArrayMap; import android.util.ArraySet; -import com.android.internal.util.Preconditions; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -102,15 +100,11 @@ public final class GetByDocumentIdRequest { return mTypePropertyPathsMap; } - /** - * Builder for {@link GetByDocumentIdRequest} objects. - * - *

Once {@link #build} is called, the instance can no longer be used. - */ + /** Builder for {@link GetByDocumentIdRequest} objects. */ public static final class Builder { private final String mNamespace; - private final Set mIds = new ArraySet<>(); - private final Map> mProjectionTypePropertyPaths = new ArrayMap<>(); + private ArraySet mIds = new ArraySet<>(); + private ArrayMap> mProjectionTypePropertyPaths = new ArrayMap<>(); private boolean mBuilt = false; /** Creates a {@link GetByDocumentIdRequest.Builder} instance. */ @@ -118,26 +112,19 @@ public final class GetByDocumentIdRequest { mNamespace = Objects.requireNonNull(namespace); } - /** - * Adds one or more document IDs to the request. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Adds one or more document IDs to the request. */ @NonNull public Builder addIds(@NonNull String... ids) { Objects.requireNonNull(ids); + resetIfBuilt(); return addIds(Arrays.asList(ids)); } - /** - * Adds a collection of IDs to the request. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Adds a collection of IDs to the request. */ @NonNull public Builder addIds(@NonNull Collection ids) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(ids); + resetIfBuilt(); mIds.addAll(ids); return this; } @@ -156,15 +143,14 @@ public final class GetByDocumentIdRequest { * apply to all results, excepting any types that have their own, specific property paths * set. * - * @throws IllegalStateException if the builder has already been used. * @see SearchSpec.Builder#addProjection */ @NonNull public Builder addProjection( @NonNull String schemaType, @NonNull Collection propertyPaths) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(schemaType); Objects.requireNonNull(propertyPaths); + resetIfBuilt(); List propertyPathsList = new ArrayList<>(propertyPaths.size()); for (String propertyPath : propertyPaths) { Objects.requireNonNull(propertyPath); @@ -174,16 +160,23 @@ public final class GetByDocumentIdRequest { return this; } - /** - * Builds a new {@link GetByDocumentIdRequest}. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Builds a new {@link GetByDocumentIdRequest}. */ @NonNull public GetByDocumentIdRequest build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); mBuilt = true; - return new GetByDocumentIdRequest(mNamespace, mIds, mProjectionTypePropertyPaths); + return new GetByDocumentIdRequest( + mNamespace, new ArraySet<>(mIds), new ArrayMap<>(mProjectionTypePropertyPaths)); + } + + private void resetIfBuilt() { + if (mBuilt) { + mIds = new ArraySet<>(mIds); + // No need to clone each propertyPathsList inside mProjectionTypePropertyPaths since + // the builder only replaces it, never adds to it. So even if the builder is used + // again, the previous one will remain with the object. + mProjectionTypePropertyPaths = new ArrayMap<>(mProjectionTypePropertyPaths); + mBuilt = false; + } } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java index 6f8cbe84ab505..8816c787673b0 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java @@ -21,8 +21,6 @@ import android.annotation.NonNull; import android.os.Bundle; import android.util.ArraySet; -import com.android.internal.util.Preconditions; - import java.util.ArrayList; import java.util.Objects; import java.util.Set; @@ -76,8 +74,8 @@ public class GetSchemaResponse { /** Builder for {@link GetSchemaResponse} objects. */ public static final class Builder { private int mVersion = 0; + private ArrayList mSchemaBundles = new ArrayList<>(); private boolean mBuilt = false; - private final ArrayList mSchemaBundles = new ArrayList<>(); /** * Sets the database overall schema version. @@ -86,6 +84,7 @@ public class GetSchemaResponse { */ @NonNull public Builder setVersion(@IntRange(from = 0) int version) { + resetIfBuilt(); mVersion = version; return this; } @@ -93,6 +92,8 @@ public class GetSchemaResponse { /** Adds one {@link AppSearchSchema} to the schema list. */ @NonNull public Builder addSchema(@NonNull AppSearchSchema schema) { + Objects.requireNonNull(schema); + resetIfBuilt(); mSchemaBundles.add(schema.getBundle()); return this; } @@ -100,12 +101,18 @@ public class GetSchemaResponse { /** Builds a {@link GetSchemaResponse} object. */ @NonNull public GetSchemaResponse build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Bundle bundle = new Bundle(); bundle.putInt(VERSION_FIELD, mVersion); bundle.putParcelableArrayList(SCHEMAS_FIELD, mSchemaBundles); mBuilt = true; return new GetSchemaResponse(bundle); } + + private void resetIfBuilt() { + if (mBuilt) { + mSchemaBundles = new ArrayList<>(mSchemaBundles); + mBuilt = false; + } + } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java index b49e0e8ca2cfc..342412882981b 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java @@ -19,8 +19,6 @@ package android.app.appsearch; import android.annotation.NonNull; -import com.android.internal.util.Preconditions; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -46,50 +44,41 @@ public final class PutDocumentsRequest { return Collections.unmodifiableList(mDocuments); } - /** - * Builder for {@link PutDocumentsRequest} objects. - * - *

Once {@link #build} is called, the instance can no longer be used. - */ + /** Builder for {@link PutDocumentsRequest} objects. */ public static final class Builder { - private final List mDocuments = new ArrayList<>(); + private ArrayList mDocuments = new ArrayList<>(); private boolean mBuilt = false; - /** - * Adds one or more {@link GenericDocument} objects to the request. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Adds one or more {@link GenericDocument} objects to the request. */ @NonNull public Builder addGenericDocuments(@NonNull GenericDocument... documents) { Objects.requireNonNull(documents); + resetIfBuilt(); return addGenericDocuments(Arrays.asList(documents)); } - /** - * Adds a collection of {@link GenericDocument} objects to the request. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Adds a collection of {@link GenericDocument} objects to the request. */ @NonNull public Builder addGenericDocuments( @NonNull Collection documents) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(documents); + resetIfBuilt(); mDocuments.addAll(documents); return this; } - /** - * Creates a new {@link PutDocumentsRequest} object. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Creates a new {@link PutDocumentsRequest} object. */ @NonNull public PutDocumentsRequest build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); mBuilt = true; return new PutDocumentsRequest(mDocuments); } + + private void resetIfBuilt() { + if (mBuilt) { + mDocuments = new ArrayList<>(mDocuments); + mBuilt = false; + } + } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java index 1afbe27116ca8..b86fd27dd1f40 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java @@ -19,8 +19,6 @@ package android.app.appsearch; import android.annotation.NonNull; import android.util.ArraySet; -import com.android.internal.util.Preconditions; - import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -54,14 +52,10 @@ public final class RemoveByDocumentIdRequest { return Collections.unmodifiableSet(mIds); } - /** - * Builder for {@link RemoveByDocumentIdRequest} objects. - * - *

Once {@link #build} is called, the instance can no longer be used. - */ + /** Builder for {@link RemoveByDocumentIdRequest} objects. */ public static final class Builder { private final String mNamespace; - private final Set mIds = new ArraySet<>(); + private ArraySet mIds = new ArraySet<>(); private boolean mBuilt = false; /** Creates a {@link RemoveByDocumentIdRequest.Builder} instance. */ @@ -69,40 +63,35 @@ public final class RemoveByDocumentIdRequest { mNamespace = Objects.requireNonNull(namespace); } - /** - * Adds one or more document IDs to the request. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Adds one or more document IDs to the request. */ @NonNull public Builder addIds(@NonNull String... ids) { Objects.requireNonNull(ids); + resetIfBuilt(); return addIds(Arrays.asList(ids)); } - /** - * Adds a collection of IDs to the request. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Adds a collection of IDs to the request. */ @NonNull public Builder addIds(@NonNull Collection ids) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(ids); + resetIfBuilt(); mIds.addAll(ids); return this; } - /** - * Builds a new {@link RemoveByDocumentIdRequest}. - * - * @throws IllegalStateException if the builder has already been used. - */ + /** Builds a new {@link RemoveByDocumentIdRequest}. */ @NonNull public RemoveByDocumentIdRequest build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); mBuilt = true; return new RemoveByDocumentIdRequest(mNamespace, mIds); } + + private void resetIfBuilt() { + if (mBuilt) { + mIds = new ArraySet<>(mIds); + mBuilt = false; + } + } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java index 3947ba78cdd5f..b6575c2030ff0 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java @@ -19,8 +19,6 @@ package android.app.appsearch; import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; -import com.android.internal.util.Preconditions; - import java.util.Objects; /** @@ -94,7 +92,6 @@ public final class ReportSystemUsageRequest { private final String mNamespace; private final String mDocumentId; private Long mUsageTimestampMillis; - private boolean mBuilt = false; /** Creates a {@link ReportSystemUsageRequest.Builder} instance. */ public Builder( @@ -116,29 +113,20 @@ public final class ReportSystemUsageRequest { * *

If unset, this defaults to the current timestamp at the time that the {@link * ReportSystemUsageRequest} is constructed. - * - * @throws IllegalStateException if the builder has already been used */ @NonNull public ReportSystemUsageRequest.Builder setUsageTimestampMillis( @CurrentTimeMillisLong long usageTimestampMillis) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); mUsageTimestampMillis = usageTimestampMillis; return this; } - /** - * Builds a new {@link ReportSystemUsageRequest}. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Builds a new {@link ReportSystemUsageRequest}. */ @NonNull public ReportSystemUsageRequest build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); if (mUsageTimestampMillis == null) { mUsageTimestampMillis = System.currentTimeMillis(); } - mBuilt = true; return new ReportSystemUsageRequest( mPackageName, mDatabase, mNamespace, mDocumentId, mUsageTimestampMillis); } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java index 5cb59b3030ee6..59fa6e0743f65 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java @@ -20,8 +20,6 @@ import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; -import com.android.internal.util.Preconditions; - import java.util.Objects; /** @@ -72,7 +70,6 @@ public final class ReportUsageRequest { // TODO(b/181887768): Make this final private String mDocumentId; private Long mUsageTimestampMillis; - private boolean mBuilt = false; /** Creates a {@link ReportUsageRequest.Builder} instance. */ public Builder(@NonNull String namespace, @NonNull String documentId) { @@ -122,29 +119,20 @@ public final class ReportUsageRequest { * *

If unset, this defaults to the current timestamp at the time that the {@link * ReportUsageRequest} is constructed. - * - * @throws IllegalStateException if the builder has already been used */ @NonNull public ReportUsageRequest.Builder setUsageTimestampMillis( @CurrentTimeMillisLong long usageTimestampMillis) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); mUsageTimestampMillis = usageTimestampMillis; return this; } - /** - * Builds a new {@link ReportUsageRequest}. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Builds a new {@link ReportUsageRequest}. */ @NonNull public ReportUsageRequest build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); if (mUsageTimestampMillis == null) { mUsageTimestampMillis = System.currentTimeMillis(); } - mBuilt = true; return new ReportUsageRequest(mNamespace, mDocumentId, mUsageTimestampMillis); } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java index 9a1796cbe94e3..0d186f26a4e53 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java @@ -164,10 +164,12 @@ public final class SearchResult { /** Builder for {@link SearchResult} objects. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private final ArrayList mMatchInfos = new ArrayList<>(); - - private boolean mBuilt; + private final String mPackageName; + private final String mDatabaseName; + private ArrayList mMatchInfoBundles = new ArrayList<>(); + private GenericDocument mGenericDocument; + private double mRankingSignal; + private boolean mBuilt = false; /** * Constructs a new builder for {@link SearchResult} objects. @@ -176,19 +178,16 @@ public final class SearchResult { * @param databaseName the database name the matched document belongs to. */ public Builder(@NonNull String packageName, @NonNull String databaseName) { - mBundle.putString(PACKAGE_NAME_FIELD, Objects.requireNonNull(packageName)); - mBundle.putString(DATABASE_NAME_FIELD, Objects.requireNonNull(databaseName)); + mPackageName = Objects.requireNonNull(packageName); + mDatabaseName = Objects.requireNonNull(databaseName); } - /** - * Sets the document which matched. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Sets the document which matched. */ @NonNull public Builder setGenericDocument(@NonNull GenericDocument document) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putBundle(DOCUMENT_FIELD, document.getBundle()); + Objects.requireNonNull(document); + resetIfBuilt(); + mGenericDocument = document; return this; } @@ -202,34 +201,41 @@ public final class SearchResult { /** Adds another match to this SearchResult. */ @NonNull public Builder addMatchInfo(@NonNull MatchInfo matchInfo) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkState( matchInfo.mDocument == null, "This MatchInfo is already associated with a SearchResult and can't be " + "reassigned"); - mMatchInfos.add(matchInfo.mBundle); + resetIfBuilt(); + mMatchInfoBundles.add(matchInfo.mBundle); return this; } /** Sets the ranking signal of the matched document in this SearchResult. */ @NonNull public Builder setRankingSignal(double rankingSignal) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putDouble(RANKING_SIGNAL_FIELD, rankingSignal); + resetIfBuilt(); + mRankingSignal = rankingSignal; return this; } - /** - * Constructs a new {@link SearchResult}. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link SearchResult}. */ @NonNull public SearchResult build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putParcelableArrayList(MATCH_INFOS_FIELD, mMatchInfos); + Bundle bundle = new Bundle(); + bundle.putString(PACKAGE_NAME_FIELD, mPackageName); + bundle.putString(DATABASE_NAME_FIELD, mDatabaseName); + bundle.putBundle(DOCUMENT_FIELD, mGenericDocument.getBundle()); + bundle.putDouble(RANKING_SIGNAL_FIELD, mRankingSignal); + bundle.putParcelableArrayList(MATCH_INFOS_FIELD, mMatchInfoBundles); mBuilt = true; - return new SearchResult(mBundle); + return new SearchResult(bundle); + } + + private void resetIfBuilt() { + if (mBuilt) { + mMatchInfoBundles = new ArrayList<>(mMatchInfoBundles); + mBuilt = false; + } } } @@ -441,8 +447,9 @@ public final class SearchResult { /** Builder for {@link MatchInfo} objects. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private final String mPropertyPath; + private MatchRange mExactMatchRange = new MatchRange(0, 0); + private MatchRange mSnippetRange = new MatchRange(0, 0); /** * Creates a new {@link MatchInfo.Builder} reporting a match with the given property @@ -458,49 +465,33 @@ public final class SearchResult { * which property in the document these snippets correspond to. */ public Builder(@NonNull String propertyPath) { - mBundle.putString( - SearchResult.MatchInfo.PROPERTY_PATH_FIELD, - Objects.requireNonNull(propertyPath)); + mPropertyPath = Objects.requireNonNull(propertyPath); } - /** - * Sets the exact {@link MatchRange} corresponding to the given entry. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Sets the exact {@link MatchRange} corresponding to the given entry. */ @NonNull public Builder setExactMatchRange(@NonNull MatchRange matchRange) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - Objects.requireNonNull(matchRange); - mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, matchRange.getStart()); - mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, matchRange.getEnd()); + mExactMatchRange = Objects.requireNonNull(matchRange); return this; } - /** - * Sets the snippet {@link MatchRange} corresponding to the given entry. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Sets the snippet {@link MatchRange} corresponding to the given entry. */ @NonNull public Builder setSnippetRange(@NonNull MatchRange matchRange) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - Objects.requireNonNull(matchRange); - mBundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, matchRange.getStart()); - mBundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, matchRange.getEnd()); + mSnippetRange = Objects.requireNonNull(matchRange); return this; } - /** - * Constructs a new {@link MatchInfo}. - * - * @throws IllegalStateException if the builder has already been used - */ + /** Constructs a new {@link MatchInfo}. */ @NonNull public MatchInfo build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new MatchInfo(mBundle, /*document=*/ null); + Bundle bundle = new Bundle(); + bundle.putString(SearchResult.MatchInfo.PROPERTY_PATH_FIELD, mPropertyPath); + bundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, mExactMatchRange.getStart()); + bundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, mExactMatchRange.getEnd()); + bundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, mSnippetRange.getStart()); + bundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, mSnippetRange.getEnd()); + return new MatchInfo(bundle, /*document=*/ null); } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java index 1c57c75307833..5abd4f69e28f6 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SuppressLint; +import android.app.appsearch.util.BundleUtil; import android.os.Bundle; import android.util.ArrayMap; @@ -310,22 +311,22 @@ public final class SearchSpec { /** Builder for {@link SearchSpec objects}. */ public static final class Builder { + private ArrayList mSchemas = new ArrayList<>(); + private ArrayList mNamespaces = new ArrayList<>(); + private ArrayList mPackageNames = new ArrayList<>(); + private Bundle mProjectionTypePropertyMasks = new Bundle(); - private final Bundle mBundle; - private final ArrayList mSchemas = new ArrayList<>(); - private final ArrayList mNamespaces = new ArrayList<>(); - private final ArrayList mPackageNames = new ArrayList<>(); - private final Bundle mProjectionTypePropertyMasks = new Bundle(); + private int mResultCountPerPage = DEFAULT_NUM_PER_PAGE; + private @TermMatch int mTermMatchType = TERM_MATCH_PREFIX; + private int mSnippetCount = 0; + private int mSnippetCountPerProperty = MAX_SNIPPET_PER_PROPERTY_COUNT; + private int mMaxSnippetSize = 0; + private @RankingStrategy int mRankingStrategy = RANKING_STRATEGY_NONE; + private @Order int mOrder = ORDER_DESCENDING; + private @GroupingType int mGroupingTypeFlags = 0; + private int mGroupingLimit = 0; private boolean mBuilt = false; - /** Creates a new {@link SearchSpec.Builder}. */ - public Builder() { - mBundle = new Bundle(); - mBundle.putInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE); - mBundle.putInt(TERM_MATCH_TYPE_FIELD, TERM_MATCH_PREFIX); - mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, MAX_SNIPPET_PER_PROPERTY_COUNT); - } - /** * Indicates how the query terms should match {@code TermMatchCode} in the index. * @@ -333,11 +334,11 @@ public final class SearchSpec { * SearchSpec#TERM_MATCH_PREFIX}. */ @NonNull - public Builder setTermMatch(@TermMatch int termMatchTypeCode) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); + public Builder setTermMatch(@TermMatch int termMatchType) { Preconditions.checkArgumentInRange( - termMatchTypeCode, TERM_MATCH_EXACT_ONLY, TERM_MATCH_PREFIX, "Term match type"); - mBundle.putInt(TERM_MATCH_TYPE_FIELD, termMatchTypeCode); + termMatchType, TERM_MATCH_EXACT_ONLY, TERM_MATCH_PREFIX, "Term match type"); + resetIfBuilt(); + mTermMatchType = termMatchType; return this; } @@ -350,7 +351,7 @@ public final class SearchSpec { @NonNull public Builder addFilterSchemas(@NonNull String... schemas) { Objects.requireNonNull(schemas); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); return addFilterSchemas(Arrays.asList(schemas)); } @@ -363,7 +364,7 @@ public final class SearchSpec { @NonNull public Builder addFilterSchemas(@NonNull Collection schemas) { Objects.requireNonNull(schemas); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); mSchemas.addAll(schemas); return this; } @@ -377,7 +378,7 @@ public final class SearchSpec { @NonNull public Builder addFilterNamespaces(@NonNull String... namespaces) { Objects.requireNonNull(namespaces); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); return addFilterNamespaces(Arrays.asList(namespaces)); } @@ -390,7 +391,7 @@ public final class SearchSpec { @NonNull public Builder addFilterNamespaces(@NonNull Collection namespaces) { Objects.requireNonNull(namespaces); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); mNamespaces.addAll(namespaces); return this; } @@ -406,7 +407,7 @@ public final class SearchSpec { @NonNull public Builder addFilterPackageNames(@NonNull String... packageNames) { Objects.requireNonNull(packageNames); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); return addFilterPackageNames(Arrays.asList(packageNames)); } @@ -421,7 +422,7 @@ public final class SearchSpec { @NonNull public Builder addFilterPackageNames(@NonNull Collection packageNames) { Objects.requireNonNull(packageNames); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); mPackageNames.addAll(packageNames); return this; } @@ -433,23 +434,24 @@ public final class SearchSpec { */ @NonNull public SearchSpec.Builder setResultCountPerPage( - @IntRange(from = 0, to = MAX_NUM_PER_PAGE) int numPerPage) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - Preconditions.checkArgumentInRange(numPerPage, 0, MAX_NUM_PER_PAGE, "NumPerPage"); - mBundle.putInt(NUM_PER_PAGE_FIELD, numPerPage); + @IntRange(from = 0, to = MAX_NUM_PER_PAGE) int resultCountPerPage) { + Preconditions.checkArgumentInRange( + resultCountPerPage, 0, MAX_NUM_PER_PAGE, "resultCountPerPage"); + resetIfBuilt(); + mResultCountPerPage = resultCountPerPage; return this; } /** Sets ranking strategy for AppSearch results. */ @NonNull public Builder setRankingStrategy(@RankingStrategy int rankingStrategy) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( rankingStrategy, RANKING_STRATEGY_NONE, RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP, "Result ranking strategy"); - mBundle.putInt(RANKING_STRATEGY_FIELD, rankingStrategy); + resetIfBuilt(); + mRankingStrategy = rankingStrategy; return this; } @@ -461,10 +463,10 @@ public final class SearchSpec { */ @NonNull public Builder setOrder(@Order int order) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( order, ORDER_DESCENDING, ORDER_ASCENDING, "Result ranking order"); - mBundle.putInt(ORDER_FIELD, order); + resetIfBuilt(); + mOrder = order; return this; } @@ -481,9 +483,9 @@ public final class SearchSpec { @NonNull public SearchSpec.Builder setSnippetCount( @IntRange(from = 0, to = MAX_SNIPPET_COUNT) int snippetCount) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange(snippetCount, 0, MAX_SNIPPET_COUNT, "snippetCount"); - mBundle.putInt(SNIPPET_COUNT_FIELD, snippetCount); + resetIfBuilt(); + mSnippetCount = snippetCount; return this; } @@ -502,13 +504,13 @@ public final class SearchSpec { public SearchSpec.Builder setSnippetCountPerProperty( @IntRange(from = 0, to = MAX_SNIPPET_PER_PROPERTY_COUNT) int snippetCountPerProperty) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( snippetCountPerProperty, 0, MAX_SNIPPET_PER_PROPERTY_COUNT, "snippetCountPerProperty"); - mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, snippetCountPerProperty); + resetIfBuilt(); + mSnippetCountPerProperty = snippetCountPerProperty; return this; } @@ -527,10 +529,10 @@ public final class SearchSpec { @NonNull public SearchSpec.Builder setMaxSnippetSize( @IntRange(from = 0, to = MAX_SNIPPET_SIZE_LIMIT) int maxSnippetSize) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Preconditions.checkArgumentInRange( maxSnippetSize, 0, MAX_SNIPPET_SIZE_LIMIT, "maxSnippetSize"); - mBundle.putInt(MAX_SNIPPET_FIELD, maxSnippetSize); + resetIfBuilt(); + mMaxSnippetSize = maxSnippetSize; return this; } @@ -599,9 +601,9 @@ public final class SearchSpec { @NonNull public SearchSpec.Builder addProjection( @NonNull String schema, @NonNull Collection propertyPaths) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(schema); Objects.requireNonNull(propertyPaths); + resetIfBuilt(); ArrayList propertyPathsArrayList = new ArrayList<>(propertyPaths.size()); for (String propertyPath : propertyPaths) { Objects.requireNonNull(propertyPath); @@ -634,25 +636,41 @@ public final class SearchSpec { public Builder setResultGrouping(@GroupingType int groupingTypeFlags, int limit) { Preconditions.checkState( groupingTypeFlags != 0, "Result grouping type cannot be zero."); - mBundle.putInt(RESULT_GROUPING_TYPE_FLAGS, groupingTypeFlags); - mBundle.putInt(RESULT_GROUPING_LIMIT, limit); + resetIfBuilt(); + mGroupingTypeFlags = groupingTypeFlags; + mGroupingLimit = limit; return this; } - /** - * Constructs a new {@link SearchSpec} from the contents of this builder. - * - *

After calling this method, the builder must no longer be used. - */ + /** Constructs a new {@link SearchSpec} from the contents of this builder. */ @NonNull public SearchSpec build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces); - mBundle.putStringArrayList(SCHEMA_FIELD, mSchemas); - mBundle.putStringArrayList(PACKAGE_NAME_FIELD, mPackageNames); - mBundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks); + Bundle bundle = new Bundle(); + bundle.putStringArrayList(SCHEMA_FIELD, mSchemas); + bundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces); + bundle.putStringArrayList(PACKAGE_NAME_FIELD, mPackageNames); + bundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks); + bundle.putInt(NUM_PER_PAGE_FIELD, mResultCountPerPage); + bundle.putInt(TERM_MATCH_TYPE_FIELD, mTermMatchType); + bundle.putInt(SNIPPET_COUNT_FIELD, mSnippetCount); + bundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, mSnippetCountPerProperty); + bundle.putInt(MAX_SNIPPET_FIELD, mMaxSnippetSize); + bundle.putInt(RANKING_STRATEGY_FIELD, mRankingStrategy); + bundle.putInt(ORDER_FIELD, mOrder); + bundle.putInt(RESULT_GROUPING_TYPE_FLAGS, mGroupingTypeFlags); + bundle.putInt(RESULT_GROUPING_LIMIT, mGroupingLimit); mBuilt = true; - return new SearchSpec(mBundle); + return new SearchSpec(bundle); + } + + private void resetIfBuilt() { + if (mBuilt) { + mSchemas = new ArrayList<>(mSchemas); + mNamespaces = new ArrayList<>(mNamespaces); + mPackageNames = new ArrayList<>(mPackageNames); + mProjectionTypePropertyMasks = BundleUtil.deepCopy(mProjectionTypePropertyMasks); + mBuilt = false; + } } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java index 275b2c337c3ca..96002c5291eed 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java @@ -167,17 +167,13 @@ public final class SetSchemaRequest { return mVersion; } - /** - * Builder for {@link SetSchemaRequest} objects. - * - *

Once {@link #build} is called, the instance can no longer be used. - */ + /** Builder for {@link SetSchemaRequest} objects. */ public static final class Builder { - private final Set mSchemas = new ArraySet<>(); - private final Set mSchemasNotDisplayedBySystem = new ArraySet<>(); - private final Map> mSchemasVisibleToPackages = + private ArraySet mSchemas = new ArraySet<>(); + private ArraySet mSchemasNotDisplayedBySystem = new ArraySet<>(); + private ArrayMap> mSchemasVisibleToPackages = new ArrayMap<>(); - private final Map mMigrators = new ArrayMap<>(); + private ArrayMap mMigrators = new ArrayMap<>(); private boolean mForceOverride = false; private int mVersion = 1; private boolean mBuilt = false; @@ -188,12 +184,11 @@ public final class SetSchemaRequest { *

An {@link AppSearchSchema} object represents one type of structured data. * *

Any documents of these types will be displayed on system UI surfaces by default. - * - * @throws IllegalStateException if the builder has already been used. */ @NonNull public Builder addSchemas(@NonNull AppSearchSchema... schemas) { Objects.requireNonNull(schemas); + resetIfBuilt(); return addSchemas(Arrays.asList(schemas)); } @@ -201,13 +196,11 @@ public final class SetSchemaRequest { * Adds a collection of {@link AppSearchSchema} objects to the schema. * *

An {@link AppSearchSchema} object represents one type of structured data. - * - * @throws IllegalStateException if the builder has already been used. */ @NonNull public Builder addSchemas(@NonNull Collection schemas) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Objects.requireNonNull(schemas); + resetIfBuilt(); mSchemas.addAll(schemas); return this; } @@ -225,7 +218,6 @@ public final class SetSchemaRequest { * @param schemaType The name of an {@link AppSearchSchema} within the same {@link * SetSchemaRequest}, which will be configured. * @param displayed Whether documents of this type will be displayed on system UI surfaces. - * @throws IllegalStateException if the builder has already been used. */ // Merged list available from getSchemasNotDisplayedBySystem @SuppressLint("MissingGetterMatchingBuilder") @@ -233,8 +225,7 @@ public final class SetSchemaRequest { public Builder setSchemaTypeDisplayedBySystem( @NonNull String schemaType, boolean displayed) { Objects.requireNonNull(schemaType); - Preconditions.checkState(!mBuilt, "Builder has already been used"); - + resetIfBuilt(); if (displayed) { mSchemasNotDisplayedBySystem.remove(schemaType); } else { @@ -262,7 +253,6 @@ public final class SetSchemaRequest { * @param schemaType The schema type to set visibility on. * @param visible Whether the {@code schemaType} will be visible or not. * @param packageIdentifier Represents the package that will be granted visibility. - * @throws IllegalStateException if the builder has already been used. */ // Merged list available from getSchemasVisibleToPackages @SuppressLint("MissingGetterMatchingBuilder") @@ -273,7 +263,7 @@ public final class SetSchemaRequest { @NonNull PackageIdentifier packageIdentifier) { Objects.requireNonNull(schemaType); Objects.requireNonNull(packageIdentifier); - Preconditions.checkState(!mBuilt, "Builder has already been used"); + resetIfBuilt(); Set packageIdentifiers = mSchemasVisibleToPackages.get(schemaType); if (visible) { @@ -324,6 +314,7 @@ public final class SetSchemaRequest { public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) { Objects.requireNonNull(schemaType); Objects.requireNonNull(migrator); + resetIfBuilt(); mMigrators.put(schemaType, migrator); return this; } @@ -352,6 +343,7 @@ public final class SetSchemaRequest { @NonNull public Builder setMigrators(@NonNull Map migrators) { Objects.requireNonNull(migrators); + resetIfBuilt(); mMigrators.putAll(migrators); return this; } @@ -369,6 +361,7 @@ public final class SetSchemaRequest { */ @NonNull public Builder setForceOverride(boolean forceOverride) { + resetIfBuilt(); mForceOverride = forceOverride; return this; } @@ -391,8 +384,7 @@ public final class SetSchemaRequest { * @param version A positive integer representing the version of the entire set of schemas * represents the version of the whole schema in the {@link AppSearchSession} database, * default version is 1. - * @throws IllegalStateException if the version is negative or the builder has already been - * used. + * @throws IllegalArgumentException if the version is negative. * @see AppSearchSession#setSchema * @see Migrator * @see SetSchemaRequest.Builder#setMigrator @@ -400,6 +392,7 @@ public final class SetSchemaRequest { @NonNull public Builder setVersion(@IntRange(from = 1) int version) { Preconditions.checkArgument(version >= 1, "Version must be a positive number."); + resetIfBuilt(); mVersion = version; return this; } @@ -409,12 +402,9 @@ public final class SetSchemaRequest { * * @throws IllegalArgumentException if schema types were referenced, but the corresponding * {@link AppSearchSchema} type was never added. - * @throws IllegalStateException if the builder has already been used. */ @NonNull public SetSchemaRequest build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - // Verify that any schema types with display or visibility settings refer to a real // schema. // Create a copy because we're going to remove from the set for verification purposes. @@ -440,5 +430,22 @@ public final class SetSchemaRequest { mForceOverride, mVersion); } + + private void resetIfBuilt() { + if (mBuilt) { + ArrayMap> schemasVisibleToPackages = + new ArrayMap<>(mSchemasVisibleToPackages.size()); + for (Map.Entry> entry : + mSchemasVisibleToPackages.entrySet()) { + schemasVisibleToPackages.put(entry.getKey(), new ArraySet<>(entry.getValue())); + } + mSchemasVisibleToPackages = schemasVisibleToPackages; + + mSchemas = new ArraySet<>(mSchemas); + mSchemasNotDisplayedBySystem = new ArraySet<>(mSchemasNotDisplayedBySystem); + mMigrators = new ArrayMap<>(mMigrators); + mBuilt = false; + } + } } } diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java index 7ad5fe877480e..2c75b71f36065 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java @@ -179,81 +179,88 @@ public class SetSchemaResponse { /** Builder for {@link SetSchemaResponse} objects. */ public static final class Builder { - private final ArrayList mMigrationFailures = new ArrayList<>(); - private final ArrayList mDeletedTypes = new ArrayList<>(); - private final ArrayList mMigratedTypes = new ArrayList<>(); - private final ArrayList mIncompatibleTypes = new ArrayList<>(); + private List mMigrationFailures = new ArrayList<>(); + private ArrayList mDeletedTypes = new ArrayList<>(); + private ArrayList mMigratedTypes = new ArrayList<>(); + private ArrayList mIncompatibleTypes = new ArrayList<>(); private boolean mBuilt = false; /** Adds {@link MigrationFailure}s to the list of migration failures. */ @NonNull public Builder addMigrationFailures( @NonNull Collection migrationFailures) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mMigrationFailures.addAll(Objects.requireNonNull(migrationFailures)); + Objects.requireNonNull(migrationFailures); + resetIfBuilt(); + mMigrationFailures.addAll(migrationFailures); return this; } /** Adds a {@link MigrationFailure} to the list of migration failures. */ @NonNull public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mMigrationFailures.add(Objects.requireNonNull(migrationFailure)); + Objects.requireNonNull(migrationFailure); + resetIfBuilt(); + mMigrationFailures.add(migrationFailure); return this; } /** Adds deletedTypes to the list of deleted schema types. */ @NonNull public Builder addDeletedTypes(@NonNull Collection deletedTypes) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mDeletedTypes.addAll(Objects.requireNonNull(deletedTypes)); + Objects.requireNonNull(deletedTypes); + resetIfBuilt(); + mDeletedTypes.addAll(deletedTypes); return this; } /** Adds one deletedType to the list of deleted schema types. */ @NonNull public Builder addDeletedType(@NonNull String deletedType) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mDeletedTypes.add(Objects.requireNonNull(deletedType)); + Objects.requireNonNull(deletedType); + resetIfBuilt(); + mDeletedTypes.add(deletedType); return this; } /** Adds incompatibleTypes to the list of incompatible schema types. */ @NonNull public Builder addIncompatibleTypes(@NonNull Collection incompatibleTypes) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mIncompatibleTypes.addAll(Objects.requireNonNull(incompatibleTypes)); + Objects.requireNonNull(incompatibleTypes); + resetIfBuilt(); + mIncompatibleTypes.addAll(incompatibleTypes); return this; } /** Adds one incompatibleType to the list of incompatible schema types. */ @NonNull public Builder addIncompatibleType(@NonNull String incompatibleType) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mIncompatibleTypes.add(Objects.requireNonNull(incompatibleType)); + Objects.requireNonNull(incompatibleType); + resetIfBuilt(); + mIncompatibleTypes.add(incompatibleType); return this; } /** Adds migratedTypes to the list of migrated schema types. */ @NonNull public Builder addMigratedTypes(@NonNull Collection migratedTypes) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mMigratedTypes.addAll(Objects.requireNonNull(migratedTypes)); + Objects.requireNonNull(migratedTypes); + resetIfBuilt(); + mMigratedTypes.addAll(migratedTypes); return this; } /** Adds one migratedType to the list of migrated schema types. */ @NonNull public Builder addMigratedType(@NonNull String migratedType) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mMigratedTypes.add(Objects.requireNonNull(migratedType)); + Objects.requireNonNull(migratedType); + resetIfBuilt(); + mMigratedTypes.add(migratedType); return this; } /** Builds a {@link SetSchemaResponse} object. */ @NonNull public SetSchemaResponse build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); Bundle bundle = new Bundle(); bundle.putStringArrayList(INCOMPATIBLE_TYPES_FIELD, mIncompatibleTypes); bundle.putStringArrayList(DELETED_TYPES_FIELD, mDeletedTypes); @@ -264,6 +271,16 @@ public class SetSchemaResponse { // AppSearchSession after we pass SetSchemaResponse via binder. return new SetSchemaResponse(bundle, mMigrationFailures); } + + private void resetIfBuilt() { + if (mBuilt) { + mMigrationFailures = new ArrayList<>(mMigrationFailures); + mDeletedTypes = new ArrayList<>(mDeletedTypes); + mMigratedTypes = new ArrayList<>(mMigratedTypes); + mIncompatibleTypes = new ArrayList<>(mIncompatibleTypes); + mBuilt = false; + } + } } /** diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java index 502b9391893fa..64d48281e6f83 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java @@ -19,8 +19,6 @@ package android.app.appsearch; import android.annotation.NonNull; import android.os.Bundle; -import com.android.internal.util.Preconditions; - import java.util.Objects; /** The response class of {@code AppSearchSession#getStorageInfo}. */ @@ -74,39 +72,39 @@ public class StorageInfo { /** Builder for {@link StorageInfo} objects. */ public static final class Builder { - private final Bundle mBundle = new Bundle(); - private boolean mBuilt = false; + private long mSizeBytes; + private int mAliveDocumentsCount; + private int mAliveNamespacesCount; /** Sets the size in bytes. */ @NonNull public StorageInfo.Builder setSizeBytes(long sizeBytes) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putLong(SIZE_BYTES_FIELD, sizeBytes); + mSizeBytes = sizeBytes; return this; } /** Sets the number of alive documents. */ @NonNull - public StorageInfo.Builder setAliveDocumentsCount(int numAliveDocuments) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putInt(ALIVE_DOCUMENTS_COUNT, numAliveDocuments); + public StorageInfo.Builder setAliveDocumentsCount(int aliveDocumentsCount) { + mAliveDocumentsCount = aliveDocumentsCount; return this; } /** Sets the number of alive namespaces. */ @NonNull - public StorageInfo.Builder setAliveNamespacesCount(int numAliveNamespaces) { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBundle.putInt(ALIVE_NAMESPACES_COUNT, numAliveNamespaces); + public StorageInfo.Builder setAliveNamespacesCount(int aliveNamespacesCount) { + mAliveNamespacesCount = aliveNamespacesCount; return this; } /** Builds a {@link StorageInfo} object. */ @NonNull public StorageInfo build() { - Preconditions.checkState(!mBuilt, "Builder has already been used"); - mBuilt = true; - return new StorageInfo(mBundle); + Bundle bundle = new Bundle(); + bundle.putLong(SIZE_BYTES_FIELD, mSizeBytes); + bundle.putInt(ALIVE_DOCUMENTS_COUNT, mAliveDocumentsCount); + bundle.putInt(ALIVE_NAMESPACES_COUNT, mAliveNamespacesCount); + return new StorageInfo(bundle); } } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java new file mode 100644 index 0000000000000..56a546a2e8e19 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java @@ -0,0 +1,220 @@ +/* + * Copyright 2021 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.server.appsearch.external.localstorage.stats; + +import android.annotation.NonNull; +import android.app.appsearch.AppSearchResult; + +import java.util.Objects; + +/** + * Class holds detailed stats for {@link + * android.app.appsearch.AppSearchSession#setSchema(SetSchemaRequest)}. + * + * @hide + */ +public final class SetSchemaStats { + @NonNull private final String mPackageName; + + @NonNull private final String mDatabase; + + /** + * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal + * state. + */ + @AppSearchResult.ResultCode private final int mStatusCode; + + private final int mTotalLatencyMillis; + + /** Overall time used for the native function call. */ + private final int mNativeLatencyMillis; + + /** Number of newly added schema types. */ + private final int mNewTypeCount; + + /** Number of deleted schema types. */ + private final int mDeletedTypeCount; + + /** Number of compatible schema type changes. */ + private final int mCompatibleTypeChangeCount; + + /** Number of index-incompatible schema type changes. */ + private final int mIndexIncompatibleTypeChangeCount; + + /** Number of backwards-incompatible schema type changes. */ + private final int mBackwardsIncompatibleTypeChangeCount; + + SetSchemaStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mPackageName = builder.mPackageName; + mDatabase = builder.mDatabase; + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNewTypeCount = builder.mNewTypeCount; + mDeletedTypeCount = builder.mDeletedTypeCount; + mCompatibleTypeChangeCount = builder.mCompatibleTypeChangeCount; + mIndexIncompatibleTypeChangeCount = builder.mIndexIncompatibleTypeChangeCount; + mBackwardsIncompatibleTypeChangeCount = builder.mBackwardsIncompatibleTypeChangeCount; + } + + /** Returns calling package name. */ + @NonNull + public String getPackageName() { + return mPackageName; + } + + /** Returns calling database name. */ + @NonNull + public String getDatabase() { + return mDatabase; + } + + /** Returns status of the SetSchema action. */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns the total latency of the SetSchema action. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** Returns overall time used for the native function call. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** Returns number of newly added schema types. */ + public int getNewTypeCount() { + return mNewTypeCount; + } + + /** Returns number of deleted schema types. */ + public int getDeletedTypeCount() { + return mDeletedTypeCount; + } + + /** Returns number of compatible type changes. */ + public int getCompatibleTypeChangeCount() { + return mCompatibleTypeChangeCount; + } + + /** + * Returns number of index-incompatible type change. + * + *

An index-incompatible type change is one that affects how pre-existing data should be + * searched over, such as modifying the {@code IndexingType} of an existing property. + */ + public int getIndexIncompatibleTypeChangeCount() { + return mIndexIncompatibleTypeChangeCount; + } + + /** + * Returns number of backwards-incompatible type change. + * + *

For details on what constitutes a backward-incompatible type change, please see {@link + * android.app.appsearch.SetSchemaRequest}. + */ + public int getBackwardsIncompatibleTypeChangeCount() { + return mBackwardsIncompatibleTypeChangeCount; + } + + /** Builder for {@link SetSchemaStats}. */ + public static class Builder { + @NonNull final String mPackageName; + @NonNull final String mDatabase; + @AppSearchResult.ResultCode int mStatusCode; + int mTotalLatencyMillis; + int mNativeLatencyMillis; + int mNewTypeCount; + int mDeletedTypeCount; + int mCompatibleTypeChangeCount; + int mIndexIncompatibleTypeChangeCount; + int mBackwardsIncompatibleTypeChangeCount; + + /** Constructor for the {@link Builder}. */ + public Builder(@NonNull String packageName, @NonNull String database) { + mPackageName = Objects.requireNonNull(packageName); + mDatabase = Objects.requireNonNull(database); + } + + /** Sets the status of the SetSchema action. */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets total latency for the SetSchema action. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** Sets native latency in milliseconds. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** Sets number of new types. */ + @NonNull + public Builder setNewTypeCount(int newTypeCount) { + mNewTypeCount = newTypeCount; + return this; + } + + /** Sets number of deleted types. */ + @NonNull + public Builder setDeletedTypeCount(int deletedTypeCount) { + mDeletedTypeCount = deletedTypeCount; + return this; + } + + /** Sets number of compatible type changes. */ + @NonNull + public Builder setCompatibleTypeChangeCount(int compatibleTypeChangeCount) { + mCompatibleTypeChangeCount = compatibleTypeChangeCount; + return this; + } + + /** Sets number of index-incompatible type changes. */ + @NonNull + public Builder setIndexIncompatibleTypeChangeCount(int indexIncompatibleTypeChangeCount) { + mIndexIncompatibleTypeChangeCount = indexIncompatibleTypeChangeCount; + return this; + } + + /** Sets number of backwards-incompatible type changes. */ + @NonNull + public Builder setBackwardsIncompatibleTypeChangeCount( + int backwardsIncompatibleTypeChangeCount) { + mBackwardsIncompatibleTypeChangeCount = backwardsIncompatibleTypeChangeCount; + return this; + } + + /** Builds a new {@link SetSchemaStats} from the {@link Builder}. */ + @NonNull + public SetSchemaStats build() { + return new SetSchemaStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index 277740f339c53..d07a3b9e229a1 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -Ic6be29e84e7c6f31cdae37973850bb3395920326 +Ibbf4260deb720ce724be81ee4394ea96181ee0f7 diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java index 845274d1f8440..d28d4ac269d43 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java @@ -165,43 +165,37 @@ public class AppSearchEmail extends GenericDocument { /** Sets the from address of {@link AppSearchEmail} */ @NonNull public Builder setFrom(@NonNull String from) { - setPropertyString(KEY_FROM, from); - return this; + return setPropertyString(KEY_FROM, from); } /** Sets the destination address of {@link AppSearchEmail} */ @NonNull public Builder setTo(@NonNull String... to) { - setPropertyString(KEY_TO, to); - return this; + return setPropertyString(KEY_TO, to); } /** Sets the CC list of {@link AppSearchEmail} */ @NonNull public Builder setCc(@NonNull String... cc) { - setPropertyString(KEY_CC, cc); - return this; + return setPropertyString(KEY_CC, cc); } /** Sets the BCC list of {@link AppSearchEmail} */ @NonNull public Builder setBcc(@NonNull String... bcc) { - setPropertyString(KEY_BCC, bcc); - return this; + return setPropertyString(KEY_BCC, bcc); } /** Sets the subject of {@link AppSearchEmail} */ @NonNull public Builder setSubject(@NonNull String subject) { - setPropertyString(KEY_SUBJECT, subject); - return this; + return setPropertyString(KEY_SUBJECT, subject); } /** Sets the body of {@link AppSearchEmail} */ @NonNull public Builder setBody(@NonNull String body) { - setPropertyString(KEY_BODY, body); - return this; + return setPropertyString(KEY_BODY, body); } /** Builds the {@link AppSearchEmail} object. */ diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaResponseTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaResponseTest.java new file mode 100644 index 0000000000000..0bbea42b3ee88 --- /dev/null +++ b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaResponseTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2021 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.app.appsearch; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; + +public class SetSchemaResponseTest { + @Test + public void testRebuild() { + SetSchemaResponse.MigrationFailure failure1 = + new SetSchemaResponse.MigrationFailure( + "namespace", + "failure1", + "schemaType", + AppSearchResult.newFailedResult( + AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage")); + SetSchemaResponse.MigrationFailure failure2 = + new SetSchemaResponse.MigrationFailure( + "namespace", + "failure2", + "schemaType", + AppSearchResult.newFailedResult( + AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage")); + + SetSchemaResponse original = + new SetSchemaResponse.Builder() + .addDeletedType("delete1") + .addIncompatibleType("incompatible1") + .addMigratedType("migrated1") + .addMigrationFailure(failure1) + .build(); + assertThat(original.getDeletedTypes()).containsExactly("delete1"); + assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1"); + assertThat(original.getMigratedTypes()).containsExactly("migrated1"); + assertThat(original.getMigrationFailures()).containsExactly(failure1); + + SetSchemaResponse rebuild = + original.toBuilder() + .addDeletedType("delete2") + .addIncompatibleType("incompatible2") + .addMigratedType("migrated2") + .addMigrationFailure(failure2) + .build(); + + // rebuild won't effect the original object + assertThat(original.getDeletedTypes()).containsExactly("delete1"); + assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1"); + assertThat(original.getMigratedTypes()).containsExactly("migrated1"); + assertThat(original.getMigrationFailures()).containsExactly(failure1); + + assertThat(rebuild.getDeletedTypes()).containsExactly("delete1", "delete2"); + assertThat(rebuild.getIncompatibleTypes()) + .containsExactly("incompatible1", "incompatible2"); + assertThat(rebuild.getMigratedTypes()).containsExactly("migrated1", "migrated2"); + assertThat(rebuild.getMigrationFailures()).containsExactly(failure1, failure2); + } +} diff --git a/core/tests/coretests/src/android/app/appsearch/external/exceptions/IllegalSchemaExceptionTest.java b/core/tests/coretests/src/android/app/appsearch/external/exceptions/IllegalSchemaExceptionTest.java new file mode 100644 index 0000000000000..1774d72c110a8 --- /dev/null +++ b/core/tests/coretests/src/android/app/appsearch/external/exceptions/IllegalSchemaExceptionTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2021 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.app.appsearch.exceptions; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; + +public class IllegalSchemaExceptionTest { + @Test + public void testExceptionWithMessage() { + IllegalSchemaException e = new IllegalSchemaException("ERROR MESSAGE"); + assertThat(e.getMessage()).isEqualTo("ERROR MESSAGE"); + assertThat(e).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java index 5c7ccfc458b27..2d039810446a6 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -265,4 +265,36 @@ public class AppSearchStatsTest { assertThat(sStats.getDocumentRetrievingLatencyMillis()) .isEqualTo(nativeDocumentRetrievingLatencyMillis); } + + @Test + public void testAppSearchStats_SetSchemaStats() { + int nativeLatencyMillis = 1; + int newTypeCount = 2; + int compatibleTypeChangeCount = 3; + int indexIncompatibleTypeChangeCount = 4; + int backwardsIncompatibleTypeChangeCount = 5; + final SetSchemaStats sStats = + new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE) + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .setNativeLatencyMillis(nativeLatencyMillis) + .setNewTypeCount(newTypeCount) + .setCompatibleTypeChangeCount(compatibleTypeChangeCount) + .setIndexIncompatibleTypeChangeCount(indexIncompatibleTypeChangeCount) + .setBackwardsIncompatibleTypeChangeCount( + backwardsIncompatibleTypeChangeCount) + .build(); + + assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME); + assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE); + assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount); + assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypeChangeCount); + assertThat(sStats.getIndexIncompatibleTypeChangeCount()) + .isEqualTo(indexIncompatibleTypeChangeCount); + assertThat(sStats.getBackwardsIncompatibleTypeChangeCount()) + .isEqualTo(backwardsIncompatibleTypeChangeCount); + } }