Update framework from Jetpack.

Changes included:
* 8b28ee6: Adds cts test to verify that CJK search.
* 96876cf: Display a single document selected from the documents list
* 8acd6a2: Add PackageIdentifier CTS test.
* 7e6f029: Add SearchSpec.Builder CTS tests.
* 7a545c8: Add CTS tests for AppSearchSchema property config builders.
* 9224f38: Add RemoveByDocumentIdRequest CTS tests.
* 6dadb66: Add tests for ReportUsageRequest and ReportSystemUsageRequest.
* 08b6b0a: Add StorageInfo.Builder Cts Tests
* b178f79: Add cts test for SearchResult, MatchInfo and MatchRange
* 158a0fa: Add GetByDocumentIdRequestCtsTest CTS tests.
* b3d5fb0: Logging stats for SetSchema.
* 7605e1e: Add test coverage for SetSchemaRequest.
* 55e10b2: Add test coverage for GenericDocument.
* 0038649: Allow reuse of SearchSpec.Builder.
* 1a309db: Mark testDocument_toString test as @Ignore
* d682ee2: Add test coverage to androidx.appsearch.exceptions
* 9dce38b: Refactor SetSchemaResponseCtsTest to unit test
* c24fd88: Prevent SearchSpec.Builder from copying members unless reused.
* 0b3b84f: Allow reuse of SearchResult.Builder.
* 56d897c: Allow reuse of builders related to AppSearchSchema.
* 27c774a: Allow reuse of remaining builders except GenericDocument.
* ffffb62: Add test coverage for SetSchemaResponse.
* 8b61217: Refactor CTS package to put 'cts' at the highest level.

Bug: 183574903
Bug: 179680545
Bug: 183239895
Bug: 183239507
Bug: 183239552
Bug: 183239611
Bug: 183239665
Bug: 183239677
Bug: 183239702
Bug: 183239768
Bug: 183239769
Bug: 183240150
Bug: 183239894
Bug: 183239741
Bug: 183239511
Bug: 183239590
Bug: 184396610
Bug: 182958600
Bug: 184396708
Bug: 183239760
Bug: 183239899
Bug: 183239508
Bug: 183239762
Bug: 183239705
Bug: 183240098
Bug: 173532925
Bug: 183239669
Bug: 183239682
Bug: 187424629
Bug: 183239509
Bug: 183151637
Bug: 178060626
Bug: 184575547
Bug: 184575981
Bug: 184575930
Bug: 184175556
Bug: 180481315
Bug: 183239740
Test: Presubmit
Change-Id: I5a119d5c779ac48601f88e28867fd5bc3e373065
This commit is contained in:
Alexander Dorokhine
2021-05-10 16:34:29 -07:00
parent 16864cd9df
commit a0553f4d59
19 changed files with 831 additions and 479 deletions

View File

@@ -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<Bundle> mPropertyBundles = new ArrayList<>();
private ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
private final Set<String> 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.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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}.
*
* <p>The following properties must be set, or {@link DocumentPropertyConfig} construction
* will fail:
*
* <ul>
* <li>cardinality
* <li>schemaType
* </ul>
*/
/** 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.
*
* <p>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);
}
}
}

View File

@@ -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("<null>");
} 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<Bundle> bundles = (List<Bundle>) 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("<error>");
++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();
}
/**

View File

@@ -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.
*
* <p>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<String> mIds = new ArraySet<>();
private final Map<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>();
private ArraySet<String> mIds = new ArraySet<>();
private ArrayMap<String, List<String>> 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<String> 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<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Objects.requireNonNull(schemaType);
Objects.requireNonNull(propertyPaths);
resetIfBuilt();
List<String> 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;
}
}
}
}

View File

@@ -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<Bundle> mSchemaBundles = new ArrayList<>();
private boolean mBuilt = false;
private final ArrayList<Bundle> 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;
}
}
}
}

View File

@@ -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.
*
* <p>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<GenericDocument> mDocuments = new ArrayList<>();
private ArrayList<GenericDocument> 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<? extends GenericDocument> 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;
}
}
}
}

View File

@@ -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.
*
* <p>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<String> mIds = new ArraySet<>();
private ArraySet<String> 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<String> 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;
}
}
}
}

View File

@@ -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 {
*
* <p>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);
}

View File

@@ -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 {
*
* <p>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);
}
}

View File

@@ -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<Bundle> mMatchInfos = new ArrayList<>();
private boolean mBuilt;
private final String mPackageName;
private final String mDatabaseName;
private ArrayList<Bundle> 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);
}
}
}

View File

@@ -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<String> mSchemas = new ArrayList<>();
private ArrayList<String> mNamespaces = new ArrayList<>();
private ArrayList<String> mPackageNames = new ArrayList<>();
private Bundle mProjectionTypePropertyMasks = new Bundle();
private final Bundle mBundle;
private final ArrayList<String> mSchemas = new ArrayList<>();
private final ArrayList<String> mNamespaces = new ArrayList<>();
private final ArrayList<String> 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<String> 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<String> 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<String> 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<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Objects.requireNonNull(schema);
Objects.requireNonNull(propertyPaths);
resetIfBuilt();
ArrayList<String> 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.
*
* <p>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;
}
}
}
}

View File

@@ -167,17 +167,13 @@ public final class SetSchemaRequest {
return mVersion;
}
/**
* Builder for {@link SetSchemaRequest} objects.
*
* <p>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<AppSearchSchema> mSchemas = new ArraySet<>();
private final Set<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
private ArraySet<AppSearchSchema> mSchemas = new ArraySet<>();
private ArraySet<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
private ArrayMap<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>();
private final Map<String, Migrator> mMigrators = new ArrayMap<>();
private ArrayMap<String, Migrator> mMigrators = new ArrayMap<>();
private boolean mForceOverride = false;
private int mVersion = 1;
private boolean mBuilt = false;
@@ -188,12 +184,11 @@ public final class SetSchemaRequest {
* <p>An {@link AppSearchSchema} object represents one type of structured data.
*
* <p>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.
*
* <p>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<AppSearchSchema> 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<PackageIdentifier> 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<String, Migrator> 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<String, Set<PackageIdentifier>> schemasVisibleToPackages =
new ArrayMap<>(mSchemasVisibleToPackages.size());
for (Map.Entry<String, Set<PackageIdentifier>> 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;
}
}
}
}

View File

@@ -179,81 +179,88 @@ public class SetSchemaResponse {
/** Builder for {@link SetSchemaResponse} objects. */
public static final class Builder {
private final ArrayList<MigrationFailure> mMigrationFailures = new ArrayList<>();
private final ArrayList<String> mDeletedTypes = new ArrayList<>();
private final ArrayList<String> mMigratedTypes = new ArrayList<>();
private final ArrayList<String> mIncompatibleTypes = new ArrayList<>();
private List<MigrationFailure> mMigrationFailures = new ArrayList<>();
private ArrayList<String> mDeletedTypes = new ArrayList<>();
private ArrayList<String> mMigratedTypes = new ArrayList<>();
private ArrayList<String> mIncompatibleTypes = new ArrayList<>();
private boolean mBuilt = false;
/** Adds {@link MigrationFailure}s to the list of migration failures. */
@NonNull
public Builder addMigrationFailures(
@NonNull Collection<MigrationFailure> 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<String> 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<String> 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<String> 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;
}
}
}
/**

View File

@@ -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);
}
}
}

View File

@@ -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.
*
* <p>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.
*
* <p>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);
}
}
}

View File

@@ -1 +1 @@
Ic6be29e84e7c6f31cdae37973850bb3395920326
Ibbf4260deb720ce724be81ee4394ea96181ee0f7

View File

@@ -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. */

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}