Sync AppSearch from framework.

Contains changes:
* 37a4e9: Split indexing configs into per-type configs.
* 69d6e3: Add projection to the Get api.

Bug: 175039682
Bug: 177572431
Bug: 171857731
Test: Presubmit

Change-Id: Ida457b2d617be6e85557023bfb4716ad78c8db6c
This commit is contained in:
Alexander Dorokhine
2021-01-20 15:41:25 -08:00
parent 3311711b82
commit 17e406e2fd
19 changed files with 946 additions and 400 deletions

View File

@@ -43,6 +43,15 @@ package android.app.appsearch {
method @IntRange(from=0) public int getVersion();
}
public static final class AppSearchSchema.BooleanPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
}
public static final class AppSearchSchema.BooleanPropertyConfig.Builder {
ctor public AppSearchSchema.BooleanPropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.BooleanPropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.BooleanPropertyConfig.Builder setCardinality(int);
}
public static final class AppSearchSchema.Builder {
ctor public AppSearchSchema.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.Builder addProperty(@NonNull android.app.appsearch.AppSearchSchema.PropertyConfig);
@@ -50,22 +59,58 @@ package android.app.appsearch {
method @NonNull public android.app.appsearch.AppSearchSchema.Builder setVersion(@IntRange(from=0) int);
}
public static final class AppSearchSchema.PropertyConfig {
public static final class AppSearchSchema.BytesPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
}
public static final class AppSearchSchema.BytesPropertyConfig.Builder {
ctor public AppSearchSchema.BytesPropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.BytesPropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.BytesPropertyConfig.Builder setCardinality(int);
}
public static final class AppSearchSchema.DocumentPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
method @NonNull public String getSchemaType();
method public boolean isIndexNestedProperties();
}
public static final class AppSearchSchema.DocumentPropertyConfig.Builder {
ctor public AppSearchSchema.DocumentPropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setCardinality(int);
method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setIndexNestedProperties(boolean);
method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setSchemaType(@NonNull String);
}
public static final class AppSearchSchema.DoublePropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
}
public static final class AppSearchSchema.DoublePropertyConfig.Builder {
ctor public AppSearchSchema.DoublePropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
}
public static final class AppSearchSchema.Int64PropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
}
public static final class AppSearchSchema.Int64PropertyConfig.Builder {
ctor public AppSearchSchema.Int64PropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig.Builder setCardinality(int);
}
public abstract static class AppSearchSchema.PropertyConfig {
method public int getCardinality();
method public int getDataType();
method public int getIndexingType();
method @NonNull public String getName();
method @Nullable public String getSchemaType();
method public int getTokenizerType();
field public static final int CARDINALITY_OPTIONAL = 2; // 0x2
field public static final int CARDINALITY_REPEATED = 1; // 0x1
field public static final int CARDINALITY_REQUIRED = 3; // 0x3
field public static final int DATA_TYPE_BOOLEAN = 4; // 0x4
field public static final int DATA_TYPE_BYTES = 5; // 0x5
field public static final int DATA_TYPE_DOCUMENT = 6; // 0x6
field public static final int DATA_TYPE_DOUBLE = 3; // 0x3
field public static final int DATA_TYPE_INT64 = 2; // 0x2
field public static final int DATA_TYPE_STRING = 1; // 0x1
}
public static final class AppSearchSchema.StringPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
method public int getIndexingType();
method public int getTokenizerType();
field public static final int INDEXING_TYPE_EXACT_TERMS = 1; // 0x1
field public static final int INDEXING_TYPE_NONE = 0; // 0x0
field public static final int INDEXING_TYPE_PREFIXES = 2; // 0x2
@@ -73,14 +118,12 @@ package android.app.appsearch {
field public static final int TOKENIZER_TYPE_PLAIN = 1; // 0x1
}
public static final class AppSearchSchema.PropertyConfig.Builder {
ctor public AppSearchSchema.PropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setCardinality(int);
method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setDataType(int);
method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setIndexingType(int);
method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setSchemaType(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.PropertyConfig.Builder setTokenizerType(int);
public static final class AppSearchSchema.StringPropertyConfig.Builder {
ctor public AppSearchSchema.StringPropertyConfig.Builder(@NonNull String);
method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig build();
method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setCardinality(int);
method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setIndexingType(int);
method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setTokenizerType(int);
}
public final class AppSearchSession implements java.io.Closeable {
@@ -143,11 +186,15 @@ package android.app.appsearch {
public final class GetByUriRequest {
method @NonNull public String getNamespace();
method @NonNull public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getProjections();
method @NonNull public java.util.Set<java.lang.String> getUris();
field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
}
public static final class GetByUriRequest.Builder {
ctor public GetByUriRequest.Builder();
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addProjection(@NonNull String, @NonNull java.lang.String...);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addProjection(@NonNull String, @NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.lang.String...);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.GetByUriRequest build();

View File

@@ -330,6 +330,7 @@ public class AppSearchManager {
DEFAULT_DATABASE_NAME,
request.getNamespace(),
uris,
request.getProjectionsVisibleToPackagesInternal(),
mContext.getUserId(),
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {

View File

@@ -311,8 +311,13 @@ public final class AppSearchSession implements Closeable {
Objects.requireNonNull(callback);
Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
try {
mService.getDocuments(mPackageName, mDatabaseName, request.getNamespace(),
new ArrayList<>(request.getUris()), mUserId,
mService.getDocuments(
mPackageName,
mDatabaseName,
request.getNamespace(),
new ArrayList<>(request.getUris()),
request.getProjectionsVisibleToPackagesInternal(),
mUserId,
new IAppSearchBatchResultCallback.Stub() {
public void onResult(AppSearchBatchResult result) {
executor.execute(() -> {

View File

@@ -97,6 +97,8 @@ interface IAppSearchManager {
* @param databaseName The databaseName this document resides in.
* @param namespace The namespace this document resides in.
* @param uris The URIs of the documents to retrieve
* @param typePropertyPaths A map of schema type to a list of property paths to return in the
* result.
* @param userId Id of the calling user
* @param callback
* If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
@@ -110,6 +112,7 @@ interface IAppSearchManager {
in String databaseName,
in String namespace,
in List<String> uris,
in Map<String, List<String>> typePropertyPaths,
in int userId,
in IAppSearchBatchResultCallback callback);

View File

@@ -19,6 +19,7 @@ package android.app.appsearch;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.AppSearchSchema.PropertyConfig;
import android.app.appsearch.AppSearchSchema.StringPropertyConfig;
/**
* Encapsulates a {@link GenericDocument} that represent an email.
@@ -41,46 +42,40 @@ public class AppSearchEmail extends GenericDocument {
public static final AppSearchSchema SCHEMA =
new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(
new PropertyConfig.Builder(KEY_FROM)
.setDataType(PropertyConfig.DATA_TYPE_STRING)
new StringPropertyConfig.Builder(KEY_FROM)
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
new PropertyConfig.Builder(KEY_TO)
.setDataType(PropertyConfig.DATA_TYPE_STRING)
new StringPropertyConfig.Builder(KEY_TO)
.setCardinality(PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
new PropertyConfig.Builder(KEY_CC)
.setDataType(PropertyConfig.DATA_TYPE_STRING)
new StringPropertyConfig.Builder(KEY_CC)
.setCardinality(PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
new PropertyConfig.Builder(KEY_BCC)
.setDataType(PropertyConfig.DATA_TYPE_STRING)
new StringPropertyConfig.Builder(KEY_BCC)
.setCardinality(PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
new PropertyConfig.Builder(KEY_SUBJECT)
.setDataType(PropertyConfig.DATA_TYPE_STRING)
new StringPropertyConfig.Builder(KEY_SUBJECT)
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.addProperty(
new PropertyConfig.Builder(KEY_BODY)
.setDataType(PropertyConfig.DATA_TYPE_STRING)
new StringPropertyConfig.Builder(KEY_BODY)
.setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build())
.build();

View File

@@ -98,7 +98,7 @@ public final class AppSearchSchema {
}
List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size());
for (int i = 0; i < propertyBundles.size(); i++) {
ret.add(new PropertyConfig(propertyBundles.get(i)));
ret.add(PropertyConfig.fromBundle(propertyBundles.get(i)));
}
return ret;
}
@@ -210,18 +210,15 @@ public final class AppSearchSchema {
}
/**
* Configuration for a single property (field) of a document type.
* Common configuration for a single property (field) in a Document.
*
* <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be a
* property.
*/
public static final class PropertyConfig {
private static final String NAME_FIELD = "name";
private static final String DATA_TYPE_FIELD = "dataType";
private static final String SCHEMA_TYPE_FIELD = "schemaType";
private static final String CARDINALITY_FIELD = "cardinality";
private static final String INDEXING_TYPE_FIELD = "indexingType";
private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
public abstract static class PropertyConfig {
static final String NAME_FIELD = "name";
static final String DATA_TYPE_FIELD = "dataType";
static final String CARDINALITY_FIELD = "cardinality";
/**
* Physical data-types of the contents of the property.
@@ -242,18 +239,31 @@ public final class AppSearchSchema {
@Retention(RetentionPolicy.SOURCE)
public @interface DataType {}
/** @hide */
public static final int DATA_TYPE_STRING = 1;
/** @hide */
public static final int DATA_TYPE_INT64 = 2;
/** @hide */
public static final int DATA_TYPE_DOUBLE = 3;
/** @hide */
public static final int DATA_TYPE_BOOLEAN = 4;
/** Unstructured BLOB. */
/**
* Unstructured BLOB.
*
* @hide
*/
public static final int DATA_TYPE_BYTES = 5;
/**
* Indicates that the property is itself a {@link GenericDocument}, making it part of a
* hierarchical schema. Any property using this DataType MUST have a valid {@link
* PropertyConfig#getSchemaType}.
*
* @hide
*/
public static final int DATA_TYPE_DOCUMENT = 6;
@@ -282,6 +292,97 @@ public final class AppSearchSchema {
/** Exactly one value [1]. */
public static final int CARDINALITY_REQUIRED = 3;
final Bundle mBundle;
@Nullable private Integer mHashCode;
PropertyConfig(@NonNull Bundle bundle) {
mBundle = Preconditions.checkNotNull(bundle);
}
@Override
public String toString() {
return mBundle.toString();
}
/** Returns the name of this property. */
@NonNull
public String getName() {
return mBundle.getString(NAME_FIELD, "");
}
/** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
public @DataType int getDataType() {
return mBundle.getInt(DATA_TYPE_FIELD, -1);
}
/**
* Returns the cardinality of the property (whether it is optional, required or repeated).
*/
public @Cardinality int getCardinality() {
return mBundle.getInt(CARDINALITY_FIELD, -1);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof PropertyConfig)) {
return false;
}
PropertyConfig otherProperty = (PropertyConfig) other;
return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
}
@Override
public int hashCode() {
if (mHashCode == null) {
mHashCode = BundleUtil.deepHashCode(mBundle);
}
return mHashCode;
}
/**
* Converts a {@link Bundle} into a {@link PropertyConfig} depending on its internal data
* type.
*
* <p>The bundle is not cloned.
*
* @throws IllegalArgumentException if the bundle does no contain a recognized value in its
* {@code DATA_TYPE_FIELD}.
* @hide
*/
@NonNull
public static PropertyConfig fromBundle(@NonNull Bundle propertyBundle) {
switch (propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)) {
case PropertyConfig.DATA_TYPE_STRING:
return new StringPropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_INT64:
return new Int64PropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_DOUBLE:
return new DoublePropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_BOOLEAN:
return new BooleanPropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_BYTES:
return new BytesPropertyConfig(propertyBundle);
case PropertyConfig.DATA_TYPE_DOCUMENT:
return new DocumentPropertyConfig(propertyBundle);
default:
throw new IllegalArgumentException(
"Unsupported property bundle of type "
+ propertyBundle.getInt(PropertyConfig.DATA_TYPE_FIELD)
+ "; contents: "
+ propertyBundle);
}
}
}
/** Configuration for a property of type String in a Document. */
public static final class StringPropertyConfig extends PropertyConfig {
private static final String INDEXING_TYPE_FIELD = "indexingType";
private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
/**
* Encapsulates the configurations on how AppSearch should query/index these terms.
*
@@ -296,14 +397,7 @@ public final class AppSearchSchema {
@Retention(RetentionPolicy.SOURCE)
public @interface IndexingType {}
/**
* Content in this property will not be tokenized or indexed.
*
* <p>Useful if the data type is not made up of terms (e.g. {@link
* PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES} type). None
* of the properties inside the nested property will be indexed regardless of the value of
* {@code indexingType} for the nested properties.
*/
/** Content in this property will not be tokenized or indexed. */
public static final int INDEXING_TYPE_NONE = 0;
/**
@@ -338,54 +432,16 @@ public final class AppSearchSchema {
public @interface TokenizerType {}
/**
* It is only valid for tokenizer_type to be 'NONE' if the data type is {@link
* PropertyConfig#DATA_TYPE_DOCUMENT}.
* It is only valid for tokenizer_type to be 'NONE' if {@link #getIndexingType} is {@link
* #INDEXING_TYPE_NONE}.
*/
public static final int TOKENIZER_TYPE_NONE = 0;
/** Tokenization for plain text. */
public static final int TOKENIZER_TYPE_PLAIN = 1;
final Bundle mBundle;
@Nullable private Integer mHashCode;
PropertyConfig(@NonNull Bundle bundle) {
mBundle = Preconditions.checkNotNull(bundle);
}
@Override
public String toString() {
return mBundle.toString();
}
/** Returns the name of this property. */
@NonNull
public String getName() {
return mBundle.getString(NAME_FIELD, "");
}
/** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
public @DataType int getDataType() {
return mBundle.getInt(DATA_TYPE_FIELD, -1);
}
/**
* Returns the logical schema-type of the contents of this property.
*
* <p>Only set when {@link #getDataType} is set to {@link #DATA_TYPE_DOCUMENT}. Otherwise,
* it is {@code null}.
*/
@Nullable
public String getSchemaType() {
return mBundle.getString(SCHEMA_TYPE_FIELD);
}
/**
* Returns the cardinality of the property (whether it is optional, required or repeated).
*/
public @Cardinality int getCardinality() {
return mBundle.getInt(CARDINALITY_FIELD, -1);
StringPropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
/** Returns how the property is indexed. */
@@ -398,75 +454,19 @@ public final class AppSearchSchema {
return mBundle.getInt(TOKENIZER_TYPE_FIELD);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof PropertyConfig)) {
return false;
}
PropertyConfig otherProperty = (PropertyConfig) other;
return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
}
@Override
public int hashCode() {
if (mHashCode == null) {
mHashCode = BundleUtil.deepHashCode(mBundle);
}
return mHashCode;
}
/**
* Builder for {@link PropertyConfig}.
* Builder for {@link StringPropertyConfig}.
*
* <p>The following properties must be set, or {@link PropertyConfig} construction will
* fail:
*
* <ul>
* <li>dataType
* <li>cardinality
* </ul>
*
* <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
* is also required.
* <p>{@link #setCardinality} must be called or {@link #build} will fail.
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link PropertyConfig.Builder}. */
/** Creates a new {@link StringPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
}
/**
* Type of data the property contains (e.g. string, int, bytes, etc).
*
* <p>This property must be set.
*/
@NonNull
public PropertyConfig.Builder setDataType(@DataType int dataType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(
dataType, DATA_TYPE_STRING, DATA_TYPE_DOCUMENT, "dataType");
mBundle.putInt(DATA_TYPE_FIELD, dataType);
return this;
}
/**
* The logical schema-type of the contents of this property.
*
* <p>Only required when {@link #setDataType} is set to {@link #DATA_TYPE_DOCUMENT}.
* Otherwise, it is ignored.
*/
@NonNull
public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(schemaType);
mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
return this;
mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING);
}
/**
@@ -474,8 +474,9 @@ public final class AppSearchSchema {
*
* <p>This property must be set.
*/
@SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
@NonNull
public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(
cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
@@ -487,7 +488,7 @@ public final class AppSearchSchema {
* Configures how a property should be indexed so that it can be retrieved by queries.
*/
@NonNull
public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
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");
@@ -497,7 +498,7 @@ public final class AppSearchSchema {
/** Configures how this property should be tokenized (split into words). */
@NonNull
public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
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");
@@ -505,6 +506,337 @@ public final class AppSearchSchema {
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 IllegalSchemaException if the property is not correctly populated
*/
@NonNull
public StringPropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
// TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
// of partially reimplementing some of the validation Icing does here.
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new StringPropertyConfig(mBundle);
}
}
}
/** Configuration for a property containing a 64-bit integer. */
public static final class Int64PropertyConfig extends PropertyConfig {
Int64PropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
/**
* Builder for {@link Int64PropertyConfig}.
*
* <p>{@link #setCardinality} must be called or {@link #build} will fail.
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link Int64PropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64);
}
/**
* The cardinality of the property (whether it is optional, required or repeated).
*
* <p>This property must be set.
*/
@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);
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 IllegalSchemaException if the property is not correctly populated
*/
@NonNull
public Int64PropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new Int64PropertyConfig(mBundle);
}
}
}
/** Configuration for a property containing a double-precision decimal number. */
public static final class DoublePropertyConfig extends PropertyConfig {
DoublePropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
/**
* Builder for {@link DoublePropertyConfig}.
*
* <p>{@link #setCardinality} must be called or {@link #build} will fail.
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link DoublePropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE);
}
/**
* The cardinality of the property (whether it is optional, required or repeated).
*
* <p>This property must be set.
*/
@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);
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 IllegalSchemaException if the property is not correctly populated
*/
@NonNull
public DoublePropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new DoublePropertyConfig(mBundle);
}
}
}
/** Configuration for a property containing a boolean. */
public static final class BooleanPropertyConfig extends PropertyConfig {
BooleanPropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
/**
* Builder for {@link BooleanPropertyConfig}.
*
* <p>{@link #setCardinality} must be called or {@link #build} will fail.
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link BooleanPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN);
}
/**
* The cardinality of the property (whether it is optional, required or repeated).
*
* <p>This property must be set.
*/
@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);
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 IllegalSchemaException if the property is not correctly populated
*/
@NonNull
public BooleanPropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new BooleanPropertyConfig(mBundle);
}
}
}
/** Configuration for a property containing a byte array. */
public static final class BytesPropertyConfig extends PropertyConfig {
BytesPropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
/**
* Builder for {@link BytesPropertyConfig}.
*
* <p>{@link #setCardinality} must be called or {@link #build} will fail.
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link BytesPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES);
}
/**
* The cardinality of the property (whether it is optional, required or repeated).
*
* <p>This property must be set.
*/
@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);
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 IllegalSchemaException if the property is not correctly populated
*/
@NonNull
public BytesPropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new BytesPropertyConfig(mBundle);
}
}
}
/** Configuration for a property containing another Document. */
public static final class DocumentPropertyConfig extends PropertyConfig {
private static final String SCHEMA_TYPE_FIELD = "schemaType";
private static final String INDEX_NESTED_PROPERTIES_FIELD = "indexNestedProperties";
DocumentPropertyConfig(@NonNull Bundle bundle) {
super(bundle);
}
/** Returns the logical schema-type of the contents of this document property. */
@NonNull
public String getSchemaType() {
return Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
}
/**
* Returns whether fields in the nested document should be indexed according to that
* document's schema.
*
* <p>If false, the nested document's properties are not indexed regardless of its own
* schema.
*/
public boolean isIndexNestedProperties() {
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>
*/
public static final class Builder {
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link DocumentPropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mBundle.putString(NAME_FIELD, propertyName);
mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
}
/**
* The logical schema-type of the contents of this property.
*
* <p>This property must be set.
*/
@NonNull
public DocumentPropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(schemaType);
mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
return this;
}
/**
* The cardinality of the property (whether it is optional, required or repeated).
*
* <p>This property must be set.
*/
@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);
return this;
}
/**
* Configures whether fields in the nested document should be indexed according to that
* document's schema.
*
* <p>If false, the nested document's properties are not indexed regardless of its own
* schema.
*/
@NonNull
public DocumentPropertyConfig.Builder setIndexNestedProperties(
boolean indexNestedProperties) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, indexNestedProperties);
return this;
}
/**
* Constructs a new {@link PropertyConfig} from the contents of this builder.
*
@@ -514,24 +846,16 @@ public final class AppSearchSchema {
* missing {@code dataType}).
*/
@NonNull
public PropertyConfig build() {
public DocumentPropertyConfig build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
// TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
// of partially reimplementing some of the validation Icing does here.
if (!mBundle.containsKey(DATA_TYPE_FIELD)) {
throw new IllegalSchemaException("Missing field: dataType");
}
if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()
&& mBundle.getInt(DATA_TYPE_FIELD) == DATA_TYPE_DOCUMENT) {
throw new IllegalSchemaException(
"Missing field: schemaType (required for configs with "
+ "dataType = DOCUMENT)");
if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()) {
throw new IllegalSchemaException("Missing field: schemaType");
}
if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new PropertyConfig(mBundle);
return new DocumentPropertyConfig(mBundle);
}
}
}

View File

@@ -80,9 +80,9 @@ public class GenericDocument {
/**
* The maximum number of indexed properties a document can have.
*
* <p>Indexed properties are properties where the {@link
* AppSearchSchema.PropertyConfig#getIndexingType()} constant is anything other than {@link
* AppSearchSchema.PropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
* <p>Indexed properties are properties which are strings where the {@link
* AppSearchSchema.StringPropertyConfig#getIndexingType} value is anything other than {@link
* AppSearchSchema.StringPropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
*/
public static int getMaxIndexedProperties() {
return MAX_INDEXED_PROPERTIES;

View File

@@ -17,13 +17,17 @@
package android.app.appsearch;
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;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@@ -32,12 +36,24 @@ import java.util.Set;
* @see AppSearchSession#getByUri
*/
public final class GetByUriRequest {
/**
* Schema type to be used in {@link android.app.appsearch.GetByUriRequest.Builder#addProjection}
* to apply property paths to all results, excepting any types that have had their own, specific
* property paths set.
*/
public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
private final String mNamespace;
private final Set<String> mUris;
private final Map<String, List<String>> mTypePropertyPathsMap;
GetByUriRequest(@NonNull String namespace, @NonNull Set<String> uris) {
mNamespace = namespace;
mUris = uris;
GetByUriRequest(
@NonNull String namespace,
@NonNull Set<String> uris,
@NonNull Map<String, List<String>> typePropertyPathsMap) {
mNamespace = Preconditions.checkNotNull(namespace);
mUris = Preconditions.checkNotNull(uris);
mTypePropertyPathsMap = Preconditions.checkNotNull(typePropertyPathsMap);
}
/** Returns the namespace to get documents from. */
@@ -52,10 +68,43 @@ public final class GetByUriRequest {
return Collections.unmodifiableSet(mUris);
}
/**
* Returns a map from schema type to property paths to be used for projection.
*
* <p>If the map is empty, then all properties will be retrieved for all results.
*
* <p>Calling this function repeatedly is inefficient. Prefer to retain the Map returned by this
* function, rather than calling it multiple times.
*/
@NonNull
public Map<String, List<String>> getProjections() {
Map<String, List<String>> copy = new ArrayMap<>();
for (String key : mTypePropertyPathsMap.keySet()) {
copy.put(key, new ArrayList<>(mTypePropertyPathsMap.get(key)));
}
return copy;
}
/**
* Returns a map from schema type to property paths to be used for projection.
*
* <p>If the map is empty, then all properties will be retrieved for all results.
*
* <p>A more efficient version of {@link #getProjections}, but it returns a modifiable map. This
* is not meant to be unhidden and should only be used by internal classes.
*
* @hide
*/
@NonNull
public Map<String, List<String>> getProjectionsVisibleToPackagesInternal() {
return mTypePropertyPathsMap;
}
/** Builder for {@link GetByUriRequest} objects. */
public static final class Builder {
private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
private final Set<String> mUris = new ArraySet<>();
private final Map<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>();
private boolean mBuilt = false;
/**
@@ -87,12 +136,63 @@ public final class GetByUriRequest {
return this;
}
/**
* Adds property paths for the specified type to be used for projection. If property paths
* are added for a type, then only the properties referred to will be retrieved for results
* of that type. If a property path that is specified isn't present in a result, it will be
* ignored for that result. Property paths cannot be null.
*
* <p>If no property paths are added for a particular type, then all properties of results
* of that type will be retrieved.
*
* <p>If property path is added for the {@link
* GetByUriRequest#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths will apply to
* all results, excepting any types that have their own, specific property paths set.
*
* <p>{@see SearchSpec.Builder#addProjection(String, String...)}
*/
@NonNull
public Builder addProjection(@NonNull String schemaType, @NonNull String... propertyPaths) {
Preconditions.checkNotNull(propertyPaths);
return addProjection(schemaType, Arrays.asList(propertyPaths));
}
/**
* Adds property paths for the specified type to be used for projection. If property paths
* are added for a type, then only the properties referred to will be retrieved for results
* of that type. If a property path that is specified isn't present in a result, it will be
* ignored for that result. Property paths cannot be null.
*
* <p>If no property paths are added for a particular type, then all properties of results
* of that type will be retrieved.
*
* <p>If property path is added for the {@link
* GetByUriRequest#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths will apply to
* all results, excepting any types that have their own, specific property paths set.
*
* <p>{@see SearchSpec.Builder#addProjection(String, String...)}
*/
@NonNull
public Builder addProjection(
@NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(schemaType);
Preconditions.checkNotNull(propertyPaths);
List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
for (String propertyPath : propertyPaths) {
Preconditions.checkNotNull(propertyPath);
propertyPathsList.add(propertyPath);
}
mProjectionTypePropertyPaths.put(schemaType, propertyPathsList);
return this;
}
/** Builds a new {@link GetByUriRequest}. */
@NonNull
public GetByUriRequest build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
return new GetByUriRequest(mNamespace, mUris);
return new GetByUriRequest(mNamespace, mUris, mProjectionTypePropertyPaths);
}
}
}

View File

@@ -190,6 +190,7 @@ public class AppSearchManagerService extends SystemService {
@NonNull String databaseName,
@NonNull String namespace,
@NonNull List<String> uris,
@NonNull Map<String, List<String>> typePropertyPaths,
@UserIdInt int userId,
@NonNull IAppSearchBatchResultCallback callback) {
Preconditions.checkNotNull(packageName);
@@ -208,8 +209,8 @@ public class AppSearchManagerService extends SystemService {
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
GenericDocument document =
impl.getDocument(packageName, databaseName, namespace, uri);
GenericDocument document = impl.getDocument(packageName, databaseName,
namespace, uri, typePropertyPaths);
resultBuilder.setSuccess(uri, document.getBundle());
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));

View File

@@ -21,6 +21,7 @@ import android.annotation.WorkerThread;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.GetByUriRequest;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
@@ -38,6 +39,7 @@ import com.android.server.appsearch.external.localstorage.converter.GenericDocum
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SearchResultToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter;
import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
@@ -428,6 +430,8 @@ public final class AppSearchImpl {
* @param databaseName The databaseName this document resides in.
* @param namespace The namespace this document resides in.
* @param uri The URI of the document to get.
* @param typePropertyPaths A map of schema type to a list of property paths to return in the
* result.
* @return The Document contents
* @throws AppSearchException on IcingSearchEngine error.
*/
@@ -436,16 +440,35 @@ public final class AppSearchImpl {
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String namespace,
@NonNull String uri)
@NonNull String uri,
@NonNull Map<String, List<String>> typePropertyPaths)
throws AppSearchException {
GetResultProto getResultProto;
List<TypePropertyMask> nonPrefixedPropertyMasks =
TypePropertyPathToProtoConverter.toTypePropertyMaskList(typePropertyPaths);
List<TypePropertyMask> prefixedPropertyMasks =
new ArrayList<>(nonPrefixedPropertyMasks.size());
for (int i = 0; i < nonPrefixedPropertyMasks.size(); ++i) {
TypePropertyMask typePropertyMask = nonPrefixedPropertyMasks.get(i);
String nonPrefixedType = typePropertyMask.getSchemaType();
String prefixedType =
nonPrefixedType.equals(GetByUriRequest.PROJECTION_SCHEMA_TYPE_WILDCARD)
? nonPrefixedType
: createPrefix(packageName, databaseName) + nonPrefixedType;
prefixedPropertyMasks.add(
typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
}
GetResultSpecProto getResultSpec =
GetResultSpecProto.newBuilder()
.addAllTypePropertyMasks(prefixedPropertyMasks)
.build();
mReadWriteLock.readLock().lock();
try {
getResultProto =
mIcingSearchEngineLocked.get(
createPrefix(packageName, databaseName) + namespace,
uri,
GetResultSpecProto.getDefaultInstance());
getResultSpec);
} finally {
mReadWriteLock.readLock().unlock();
}

View File

@@ -85,15 +85,14 @@ class VisibilityStore {
private static final AppSearchSchema VISIBILITY_SCHEMA =
new AppSearchSchema.Builder(VISIBILITY_TYPE)
.addProperty(
new AppSearchSchema.PropertyConfig.Builder(
new AppSearchSchema.StringPropertyConfig.Builder(
NOT_PLATFORM_SURFACEABLE_PROPERTY)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.addProperty(
new AppSearchSchema.PropertyConfig.Builder(PACKAGE_ACCESSIBLE_PROPERTY)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
new AppSearchSchema.DocumentPropertyConfig.Builder(
PACKAGE_ACCESSIBLE_PROPERTY)
.setSchemaType(PACKAGE_ACCESSIBLE_TYPE)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
@@ -107,22 +106,20 @@ class VisibilityStore {
private static final AppSearchSchema PACKAGE_ACCESSIBLE_SCHEMA =
new AppSearchSchema.Builder(PACKAGE_ACCESSIBLE_TYPE)
.addProperty(
new AppSearchSchema.PropertyConfig.Builder(PACKAGE_NAME_PROPERTY)
new AppSearchSchema.StringPropertyConfig.Builder(PACKAGE_NAME_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.build())
.addProperty(
new AppSearchSchema.PropertyConfig.Builder(SHA_256_CERT_PROPERTY)
new AppSearchSchema.BytesPropertyConfig.Builder(SHA_256_CERT_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
.build())
.addProperty(
new AppSearchSchema.PropertyConfig.Builder(ACCESSIBLE_SCHEMA_PROPERTY)
new AppSearchSchema.StringPropertyConfig.Builder(
ACCESSIBLE_SCHEMA_PROPERTY)
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.build())
.build();
@@ -238,7 +235,8 @@ class VisibilityStore {
PACKAGE_NAME,
DATABASE_NAME,
NAMESPACE,
/*uri=*/ addUriPrefix(prefix));
/*uri=*/ addUriPrefix(prefix),
/*typePropertyPaths=*/ Collections.emptyMap());
// Update platform visibility settings
String[] schemas =

View File

@@ -22,6 +22,7 @@ import android.util.Log;
import com.android.internal.util.Preconditions;
import com.google.android.icing.proto.DocumentIndexingConfig;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProtoOrBuilder;
@@ -65,7 +66,6 @@ public final class SchemaToProtoConverter {
Preconditions.checkNotNull(property);
PropertyConfigProto.Builder builder =
PropertyConfigProto.newBuilder().setPropertyName(property.getName());
StringIndexingConfig.Builder indexingConfig = StringIndexingConfig.newBuilder();
// Set dataType
@AppSearchSchema.PropertyConfig.DataType int dataType = property.getDataType();
@@ -76,12 +76,6 @@ public final class SchemaToProtoConverter {
}
builder.setDataType(dataTypeProto);
// Set schemaType
String schemaType = property.getSchemaType();
if (schemaType != null) {
builder.setSchemaType(schemaType);
}
// Set cardinality
@AppSearchSchema.PropertyConfig.Cardinality int cardinality = property.getCardinality();
PropertyConfigProto.Cardinality.Code cardinalityProto =
@@ -91,36 +85,27 @@ public final class SchemaToProtoConverter {
}
builder.setCardinality(cardinalityProto);
// Set indexingType
@AppSearchSchema.PropertyConfig.IndexingType int indexingType = property.getIndexingType();
TermMatchType.Code termMatchTypeProto;
switch (indexingType) {
case AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE:
termMatchTypeProto = TermMatchType.Code.UNKNOWN;
break;
case AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS:
termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
break;
case AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES:
termMatchTypeProto = TermMatchType.Code.PREFIX;
break;
default:
throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
}
indexingConfig.setTermMatchType(termMatchTypeProto);
if (property instanceof AppSearchSchema.StringPropertyConfig) {
AppSearchSchema.StringPropertyConfig stringProperty =
(AppSearchSchema.StringPropertyConfig) property;
StringIndexingConfig stringIndexingConfig =
StringIndexingConfig.newBuilder()
.setTermMatchType(
convertTermMatchTypeToProto(stringProperty.getIndexingType()))
.setTokenizerType(
convertTokenizerTypeToProto(stringProperty.getTokenizerType()))
.build();
builder.setStringIndexingConfig(stringIndexingConfig);
// Set tokenizerType
@AppSearchSchema.PropertyConfig.TokenizerType
int tokenizerType = property.getTokenizerType();
StringIndexingConfig.TokenizerType.Code tokenizerTypeProto =
StringIndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
if (tokenizerTypeProto == null) {
throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
} else if (property instanceof AppSearchSchema.DocumentPropertyConfig) {
AppSearchSchema.DocumentPropertyConfig documentProperty =
(AppSearchSchema.DocumentPropertyConfig) property;
builder.setSchemaType(documentProperty.getSchemaType())
.setDocumentIndexingConfig(
DocumentIndexingConfig.newBuilder()
.setIndexNestedProperties(
documentProperty.isIndexNestedProperties()));
}
indexingConfig.setTokenizerType(tokenizerTypeProto);
// Build!
builder.setStringIndexingConfig(indexingConfig);
return builder.build();
}
@@ -145,39 +130,99 @@ public final class SchemaToProtoConverter {
private static AppSearchSchema.PropertyConfig toPropertyConfig(
@NonNull PropertyConfigProto proto) {
Preconditions.checkNotNull(proto);
AppSearchSchema.PropertyConfig.Builder builder =
new AppSearchSchema.PropertyConfig.Builder(proto.getPropertyName())
.setDataType(proto.getDataType().getNumber())
switch (proto.getDataType()) {
case STRING:
return toStringPropertyConfig(proto);
case INT64:
return new AppSearchSchema.Int64PropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.build();
case DOUBLE:
return new AppSearchSchema.DoublePropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.build();
case BOOLEAN:
return new AppSearchSchema.BooleanPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.build();
case BYTES:
return new AppSearchSchema.BytesPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.build();
case DOCUMENT:
return toDocumentPropertyConfig(proto);
default:
throw new IllegalArgumentException("Invalid dataType: " + proto.getDataType());
}
}
@NonNull
private static AppSearchSchema.StringPropertyConfig toStringPropertyConfig(
@NonNull PropertyConfigProto proto) {
AppSearchSchema.StringPropertyConfig.Builder builder =
new AppSearchSchema.StringPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.setTokenizerType(
proto.getStringIndexingConfig().getTokenizerType().getNumber());
// Set schema
if (!proto.getSchemaType().isEmpty()) {
builder.setSchemaType(proto.getSchemaType());
}
// Set indexingType
@AppSearchSchema.PropertyConfig.IndexingType int indexingType;
TermMatchType.Code termMatchTypeProto = proto.getStringIndexingConfig().getTermMatchType();
switch (termMatchTypeProto) {
case UNKNOWN:
indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
break;
case EXACT_ONLY:
indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS;
break;
case PREFIX:
indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
break;
default:
// Avoid crashing in the 'read' path; we should try to interpret the document to the
// extent possible.
Log.w(TAG, "Invalid indexingType: " + termMatchTypeProto.getNumber());
indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
}
builder.setIndexingType(indexingType);
builder.setIndexingType(convertTermMatchTypeFromProto(termMatchTypeProto));
return builder.build();
}
@NonNull
private static AppSearchSchema.DocumentPropertyConfig toDocumentPropertyConfig(
@NonNull PropertyConfigProto proto) {
return new AppSearchSchema.DocumentPropertyConfig.Builder(proto.getPropertyName())
.setCardinality(proto.getCardinality().getNumber())
.setSchemaType(proto.getSchemaType())
.setIndexNestedProperties(
proto.getDocumentIndexingConfig().getIndexNestedProperties())
.build();
}
@NonNull
private static TermMatchType.Code convertTermMatchTypeToProto(
@AppSearchSchema.StringPropertyConfig.IndexingType int indexingType) {
switch (indexingType) {
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
return TermMatchType.Code.UNKNOWN;
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
return TermMatchType.Code.EXACT_ONLY;
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
return TermMatchType.Code.PREFIX;
default:
throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
}
}
@AppSearchSchema.StringPropertyConfig.IndexingType
private static int convertTermMatchTypeFromProto(@NonNull TermMatchType.Code termMatchType) {
switch (termMatchType) {
case UNKNOWN:
return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
case EXACT_ONLY:
return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS;
case PREFIX:
return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES;
default:
// Avoid crashing in the 'read' path; we should try to interpret the document to the
// extent possible.
Log.w(TAG, "Invalid indexingType: " + termMatchType.getNumber());
return AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE;
}
}
@NonNull
private static StringIndexingConfig.TokenizerType.Code convertTokenizerTypeToProto(
@AppSearchSchema.StringPropertyConfig.TokenizerType int tokenizerType) {
StringIndexingConfig.TokenizerType.Code tokenizerTypeProto =
StringIndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
if (tokenizerTypeProto == null) {
throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
}
return tokenizerTypeProto;
}
}

View File

@@ -25,10 +25,6 @@ import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
import com.google.android.icing.proto.TypePropertyMask;
import java.util.List;
import java.util.Map;
/**
* Translates a {@link SearchSpec} into icing search protos.
@@ -61,22 +57,17 @@ public final class SearchSpecToProtoConverter {
@NonNull
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
ResultSpecProto.Builder builder =
ResultSpecProto.newBuilder()
.setNumPerPage(spec.getResultCountPerPage())
.setSnippetSpec(
ResultSpecProto.SnippetSpecProto.newBuilder()
.setNumToSnippet(spec.getSnippetCount())
.setNumMatchesPerProperty(spec.getSnippetCountPerProperty())
.setMaxWindowBytes(spec.getMaxSnippetSize()));
Map<String, List<String>> projectionTypePropertyPaths = spec.getProjections();
for (Map.Entry<String, List<String>> e : projectionTypePropertyPaths.entrySet()) {
builder.addTypePropertyMasks(
TypePropertyMask.newBuilder()
.setSchemaType(e.getKey())
.addAllPaths(e.getValue()));
}
return builder.build();
return ResultSpecProto.newBuilder()
.setNumPerPage(spec.getResultCountPerPage())
.setSnippetSpec(
ResultSpecProto.SnippetSpecProto.newBuilder()
.setNumToSnippet(spec.getSnippetCount())
.setNumMatchesPerProperty(spec.getSnippetCountPerProperty())
.setMaxWindowBytes(spec.getMaxSnippetSize()))
.addAllTypePropertyMasks(
TypePropertyPathToProtoConverter.toTypePropertyMaskList(
spec.getProjections()))
.build();
}
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */

View File

@@ -0,0 +1,52 @@
/*
* 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.converter;
import android.annotation.NonNull;
import com.android.internal.util.Preconditions;
import com.google.android.icing.proto.TypePropertyMask;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Translates a <code>Map<String, List<String>></code> into <code>List<TypePropertyMask></code>.
*
* @hide
*/
public final class TypePropertyPathToProtoConverter {
private TypePropertyPathToProtoConverter() {}
/** Extracts {@link TypePropertyMask} information from a {@link Map}. */
@NonNull
public static List<TypePropertyMask> toTypePropertyMaskList(
@NonNull Map<String, List<String>> typePropertyPaths) {
Preconditions.checkNotNull(typePropertyPaths);
List<TypePropertyMask> typePropertyMasks = new ArrayList<>(typePropertyPaths.size());
for (Map.Entry<String, List<String>> e : typePropertyPaths.entrySet()) {
typePropertyMasks.add(
TypePropertyMask.newBuilder()
.setSchemaType(e.getKey())
.addAllPaths(e.getValue())
.build());
}
return typePropertyMasks;
}
}

View File

@@ -1 +1 @@
I87d10a6c5f7b8e22a633fa910385061fbca0db24
Iff96eae150c7cdd281c9ecb5d93f4ef697e89f1a

View File

@@ -28,6 +28,7 @@ import android.app.appsearch.SearchResultsShim;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
public class AppSearchTestUtils {
@@ -59,6 +60,20 @@ public class AppSearchTestUtils {
return list;
}
public static List<GenericDocument> doGet(AppSearchSessionShim session, GetByUriRequest request)
throws Exception {
AppSearchBatchResult<String, GenericDocument> result =
checkIsBatchResultSuccess(session.getByUri(request));
Set<String> uris = request.getUris();
assertThat(result.getSuccesses()).hasSize(uris.size());
assertThat(result.getFailures()).isEmpty();
List<GenericDocument> list = new ArrayList<>(uris.size());
for (String uri : uris) {
list.add(result.getSuccesses().get(uri));
}
return list;
}
public static List<GenericDocument> convertSearchResultsToDocuments(
SearchResultsShim searchResults) throws Exception {
List<SearchResult> results = searchResults.getNextPage().get();

View File

@@ -47,32 +47,24 @@ public class AppSearchPerson extends GenericDocument {
}
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_NAME)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_KEY)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_KEY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_IS_BOT)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
).addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder(KEY_IS_BOT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_IS_IMPORTANT)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
).addProperty(new AppSearchSchema.BooleanPropertyConfig.Builder(KEY_IS_IMPORTANT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).build();

View File

@@ -73,131 +73,100 @@ public class AppSearchShortcutInfo extends GenericDocument {
public static final String KEY_DISABLED_REASON = "disabledReason";
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_PACKAGE_NAME)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_PACKAGE_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ACTIVITY)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ACTIVITY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_TITLE)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TITLE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_TEXT)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_TEXT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_DISABLED_MESSAGE)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_DISABLED_MESSAGE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_CATEGORIES)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_CATEGORIES)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_INTENTS)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_INTENTS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_INTENT_PERSISTABLE_EXTRAS)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(
KEY_INTENT_PERSISTABLE_EXTRAS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_PERSON)
).addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(KEY_PERSON)
.setSchemaType(AppSearchPerson.SCHEMA_TYPE)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_LOCUS_ID)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_LOCUS_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_RANK)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_RANK)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_EXTRAS)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
).addProperty(new AppSearchSchema.BytesPropertyConfig.Builder(KEY_EXTRAS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_FLAGS)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_FLAGS)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_RES_ID)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_ICON_RES_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_RES_NAME)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ICON_RES_NAME)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_ICON_URI)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_ICON_URI)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_BITMAP_PATH)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
).addProperty(new AppSearchSchema.StringPropertyConfig.Builder(KEY_BITMAP_PATH)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.build()
).addProperty(new AppSearchSchema.PropertyConfig.Builder(KEY_DISABLED_REASON)
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
).addProperty(new AppSearchSchema.Int64PropertyConfig.Builder(KEY_DISABLED_REASON)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
.setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
.setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
.build()
).build();

View File

@@ -34,28 +34,26 @@ public class SchemaToProtoConverterTest {
new AppSearchSchema.Builder("Email")
.setVersion(12345)
.addProperty(
new AppSearchSchema.PropertyConfig.Builder("subject")
.setDataType(
AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
new AppSearchSchema.StringPropertyConfig.Builder("subject")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(
AppSearchSchema.PropertyConfig
AppSearchSchema.StringPropertyConfig
.INDEXING_TYPE_PREFIXES)
.setTokenizerType(
AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
AppSearchSchema.StringPropertyConfig
.TOKENIZER_TYPE_PLAIN)
.build())
.addProperty(
new AppSearchSchema.PropertyConfig.Builder("body")
.setDataType(
AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
new AppSearchSchema.StringPropertyConfig.Builder("body")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(
AppSearchSchema.PropertyConfig
AppSearchSchema.StringPropertyConfig
.INDEXING_TYPE_PREFIXES)
.setTokenizerType(
AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
AppSearchSchema.StringPropertyConfig
.TOKENIZER_TYPE_PLAIN)
.build())
.build();
@@ -102,26 +100,20 @@ public class SchemaToProtoConverterTest {
AppSearchSchema musicRecordingSchema =
new AppSearchSchema.Builder("MusicRecording")
.addProperty(
new AppSearchSchema.PropertyConfig.Builder("artist")
.setDataType(
AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
new AppSearchSchema.StringPropertyConfig.Builder("artist")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.setIndexingType(
AppSearchSchema.PropertyConfig
AppSearchSchema.StringPropertyConfig
.INDEXING_TYPE_PREFIXES)
.setTokenizerType(
AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
AppSearchSchema.StringPropertyConfig
.TOKENIZER_TYPE_PLAIN)
.build())
.addProperty(
new AppSearchSchema.PropertyConfig.Builder("pubDate")
.setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
new AppSearchSchema.Int64PropertyConfig.Builder("pubDate")
.setCardinality(
AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(
AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(
AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
.build())
.build();
@@ -147,14 +139,7 @@ public class SchemaToProtoConverterTest {
.setPropertyName("pubDate")
.setDataType(PropertyConfigProto.DataType.Code.INT64)
.setCardinality(
PropertyConfigProto.Cardinality.Code.OPTIONAL)
.setStringIndexingConfig(
StringIndexingConfig.newBuilder()
.setTokenizerType(
StringIndexingConfig.TokenizerType
.Code.NONE)
.setTermMatchType(
TermMatchType.Code.UNKNOWN)))
PropertyConfigProto.Cardinality.Code.OPTIONAL))
.build();
assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(musicRecordingSchema))