Merge "Merge frontend changes from Jetpack into Framework."

This commit is contained in:
Alexander Dorokhine
2020-11-02 04:54:43 +00:00
committed by Android (Google) Code Review
26 changed files with 614 additions and 453 deletions

View File

@@ -27,8 +27,6 @@ import android.app.appsearch.AppSearchSchema.PropertyConfig;
*
* <p>This class is a higher level implement of {@link GenericDocument}.
*
* <p>This class will eventually migrate to Jetpack, where it will become public API.
*
* @hide
*/
@@ -99,10 +97,9 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Get the from address of {@link AppSearchEmail}.
* Gets the from address of {@link AppSearchEmail}.
*
* @return Returns the subject of {@link AppSearchEmail} or {@code null} if it's not been set
* yet.
* @return The subject of {@link AppSearchEmail} or {@code null} if it's not been set yet.
*/
@Nullable
public String getFrom() {
@@ -110,10 +107,10 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Get the destination addresses of {@link AppSearchEmail}.
* Gets the destination addresses of {@link AppSearchEmail}.
*
* @return Returns the destination addresses of {@link AppSearchEmail} or {@code null} if it's
* not been set yet.
* @return The destination addresses of {@link AppSearchEmail} or {@code null} if it's not
* been set yet.
*/
@Nullable
public String[] getTo() {
@@ -121,10 +118,9 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Get the CC list of {@link AppSearchEmail}.
* Gets the CC list of {@link AppSearchEmail}.
*
* @return Returns the CC list of {@link AppSearchEmail} or {@code null} if it's not been set
* yet.
* @return The CC list of {@link AppSearchEmail} or {@code null} if it's not been set yet.
*/
@Nullable
public String[] getCc() {
@@ -132,10 +128,9 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Get the BCC list of {@link AppSearchEmail}.
* Gets the BCC list of {@link AppSearchEmail}.
*
* @return Returns the BCC list of {@link AppSearchEmail} or {@code null} if it's not been set
* yet.
* @return The BCC list of {@link AppSearchEmail} or {@code null} if it's not been set yet.
*/
@Nullable
public String[] getBcc() {
@@ -143,10 +138,9 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Get the subject of {@link AppSearchEmail}.
* Gets the subject of {@link AppSearchEmail}.
*
* @return Returns the value subject of {@link AppSearchEmail} or {@code null} if it's not been
* set yet.
* @return The value subject of {@link AppSearchEmail} or {@code null} if it's not been set yet.
*/
@Nullable
public String getSubject() {
@@ -154,9 +148,9 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Get the body of {@link AppSearchEmail}.
* Gets the body of {@link AppSearchEmail}.
*
* @return Returns the body of {@link AppSearchEmail} or {@code null} if it's not been set yet.
* @return The body of {@link AppSearchEmail} or {@code null} if it's not been set yet.
*/
@Nullable
public String getBody() {
@@ -169,7 +163,8 @@ public class AppSearchEmail extends GenericDocument {
public static class Builder extends GenericDocument.Builder<AppSearchEmail.Builder> {
/**
* Create a new {@link AppSearchEmail.Builder}
* Creates a new {@link AppSearchEmail.Builder}
*
* @param uri The Uri of the Email.
*/
public Builder(@NonNull String uri) {
@@ -177,56 +172,56 @@ public class AppSearchEmail extends GenericDocument {
}
/**
* Set the from address of {@link AppSearchEmail}
* Sets the from address of {@link AppSearchEmail}
*/
@NonNull
public AppSearchEmail.Builder setFrom(@NonNull String from) {
setProperty(KEY_FROM, from);
setPropertyString(KEY_FROM, from);
return this;
}
/**
* Set the destination address of {@link AppSearchEmail}
* Sets the destination address of {@link AppSearchEmail}
*/
@NonNull
public AppSearchEmail.Builder setTo(@NonNull String... to) {
setProperty(KEY_TO, to);
setPropertyString(KEY_TO, to);
return this;
}
/**
* Set the CC list of {@link AppSearchEmail}
* Sets the CC list of {@link AppSearchEmail}
*/
@NonNull
public AppSearchEmail.Builder setCc(@NonNull String... cc) {
setProperty(KEY_CC, cc);
setPropertyString(KEY_CC, cc);
return this;
}
/**
* Set the BCC list of {@link AppSearchEmail}
* Sets the BCC list of {@link AppSearchEmail}
*/
@NonNull
public AppSearchEmail.Builder setBcc(@NonNull String... bcc) {
setProperty(KEY_BCC, bcc);
setPropertyString(KEY_BCC, bcc);
return this;
}
/**
* Set the subject of {@link AppSearchEmail}
* Sets the subject of {@link AppSearchEmail}
*/
@NonNull
public AppSearchEmail.Builder setSubject(@NonNull String subject) {
setProperty(KEY_SUBJECT, subject);
setPropertyString(KEY_SUBJECT, subject);
return this;
}
/**
* Set the body of {@link AppSearchEmail}
* Sets the body of {@link AppSearchEmail}
*/
@NonNull
public AppSearchEmail.Builder setBody(@NonNull String body) {
setProperty(KEY_BODY, body);
setPropertyString(KEY_BODY, body);
return this;
}

View File

@@ -16,10 +16,12 @@
package android.app.appsearch;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.exceptions.IllegalSchemaException;
import android.util.ArraySet;
@@ -28,6 +30,8 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
@@ -39,13 +43,8 @@ import java.util.Set;
* @hide
*/
public final class AppSearchSchema {
/** @hide */
public static final String SCHEMA_TYPE_FIELD = "schemaType";
/** @hide */
public static final String PROPERTIES_FIELD = "properties";
private static final String SCHEMA_TYPE_FIELD = "schemaType";
private static final String PROPERTIES_FIELD = "properties";
private final Bundle mBundle;
@@ -71,10 +70,35 @@ public final class AppSearchSchema {
return mBundle.toString();
}
/** Returns the name of this schema type, e.g. Email. */
@NonNull
public String getSchemaTypeName() {
return mBundle.getString(SCHEMA_TYPE_FIELD, "");
}
/**
* Returns the list of {@link PropertyConfig}s that are part of this schema.
*
* <p>This method creates a new list when called.
*/
@NonNull
public List<PropertyConfig> getProperties() {
ArrayList<Bundle> propertyBundles =
mBundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD);
if (propertyBundles.isEmpty()) {
return Collections.emptyList();
}
List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size());
for (int i = 0; i < propertyBundles.size(); i++) {
ret.add(new PropertyConfig(propertyBundles.get(i)));
}
return ret;
}
/** Builder for {@link AppSearchSchema objects}. */
public static final class Builder {
private final String mTypeName;
private final ArrayList<Bundle> mProperties = new ArrayList<>();
private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
private final Set<String> mPropertyNames = new ArraySet<>();
private boolean mBuilt = false;
@@ -85,15 +109,19 @@ public final class AppSearchSchema {
}
/** Adds a property to the given type. */
// TODO(b/171360120): MissingGetterMatchingBuilder expects a method called getPropertys, but
// we provide the (correct) method getProperties. Once the bug referenced in this TODO is
// fixed, remove this SuppressLint.
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(propertyConfig);
if (!mPropertyNames.add(propertyConfig.mName)) {
throw new IllegalSchemaException(
"Property defined more than once: " + propertyConfig.mName);
String name = propertyConfig.getName();
if (!mPropertyNames.add(name)) {
throw new IllegalSchemaException("Property defined more than once: " + name);
}
mProperties.add(propertyConfig.mBundle);
mPropertyBundles.add(propertyConfig.mBundle);
return this;
}
@@ -107,7 +135,7 @@ public final class AppSearchSchema {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Bundle bundle = new Bundle();
bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mTypeName);
bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mProperties);
bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
mBuilt = true;
return new AppSearchSchema(bundle);
}
@@ -120,29 +148,12 @@ public final class AppSearchSchema {
* a property.
*/
public static final class PropertyConfig {
/** @hide */
public static final String NAME_FIELD = "name";
/** @hide */
public static final String DATA_TYPE_FIELD = "dataType";
/** @hide */
public static final String SCHEMA_TYPE_FIELD = "schemaType";
/** @hide */
public static final String CARDINALITY_FIELD = "cardinality";
/** @hide */
public static final String INDEXING_TYPE_FIELD = "indexingType";
/** @hide */
public static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
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";
/**
* Physical data-types of the contents of the property.
@@ -259,11 +270,9 @@ public final class AppSearchSchema {
/** Tokenization for plain text. */
public static final int TOKENIZER_TYPE_PLAIN = 1;
final String mName;
final Bundle mBundle;
PropertyConfig(@NonNull String name, @NonNull Bundle bundle) {
mName = Preconditions.checkNotNull(name);
PropertyConfig(@NonNull Bundle bundle) {
mBundle = Preconditions.checkNotNull(bundle);
}
@@ -272,6 +281,45 @@ public final class AppSearchSchema {
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);
}
/** Returns how the property is indexed. */
public @IndexingType int getIndexingType() {
return mBundle.getInt(INDEXING_TYPE_FIELD);
}
/** Returns how this property is tokenized (split into words). */
public @TokenizerType int getTokenizerType() {
return mBundle.getInt(TOKENIZER_TYPE_FIELD);
}
/**
* Builder for {@link PropertyConfig}.
*
@@ -286,13 +334,11 @@ public final class AppSearchSchema {
* is also required.
*/
public static final class Builder {
private final String mName;
private final Bundle mBundle = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link PropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
mName = Preconditions.checkNotNull(propertyName);
mBundle.putString(NAME_FIELD, propertyName);
}
@@ -386,7 +432,7 @@ public final class AppSearchSchema {
throw new IllegalSchemaException("Missing field: cardinality");
}
mBuilt = true;
return new PropertyConfig(mName, mBundle);
return new PropertyConfig(mBundle);
}
}
}

View File

@@ -30,6 +30,7 @@ import com.android.internal.util.Preconditions;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
/**
@@ -65,20 +66,14 @@ public class GenericDocument {
/** The default time-to-live in millisecond of a document, which is infinity. */
private static final long DEFAULT_TTL_MILLIS = 0L;
/** @hide */
public static final String PROPERTIES_FIELD = "properties";
/** @hide */
public static final String BYTE_ARRAY_FIELD = "byteArray";
static final String SCHEMA_TYPE_FIELD = "schemaType";
static final String URI_FIELD = "uri";
static final String SCORE_FIELD = "score";
static final String TTL_MILLIS_FIELD = "ttlMillis";
static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
static final String NAMESPACE_FIELD = "namespace";
private static final String PROPERTIES_FIELD = "properties";
private static final String BYTE_ARRAY_FIELD = "byteArray";
private static final String SCHEMA_TYPE_FIELD = "schemaType";
private static final String URI_FIELD = "uri";
private static final String SCORE_FIELD = "score";
private static final String TTL_MILLIS_FIELD = "ttlMillis";
private static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
private static final String NAMESPACE_FIELD = "namespace";
/**
* The maximum number of indexed properties a document can have.
@@ -190,6 +185,12 @@ public class GenericDocument {
return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE);
}
/** Returns the names of all properties defined in this document. */
@NonNull
public Set<String> getPropertyNames() {
return Collections.unmodifiableSet(mProperties.keySet());
}
/**
* Retrieves a {@link String} value by key.
*
@@ -437,8 +438,6 @@ public class GenericDocument {
@Override
public boolean equals(@Nullable Object other) {
// Check only proto's equality is sufficient here since all properties in
// mProperties are ordered by keys and stored in proto.
if (this == other) {
return true;
}
@@ -450,8 +449,8 @@ public class GenericDocument {
}
/**
* Deeply checks two bundle is equally or not.
* <p> Two bundle will be considered equally if they contains same content.
* Deeply checks two bundles are equally or not.
* <p> Two bundles will be considered equally if they contain same content.
*/
@SuppressWarnings("unchecked")
private static boolean bundleEquals(Bundle one, Bundle two) {
@@ -472,7 +471,7 @@ public class GenericDocument {
return false;
} else if (valueOne == null && (valueTwo != null || !two.containsKey(key))) {
// If we call bundle.get(key) when the 'key' doesn't actually exist in the
// bundle, we'll get back a null. So make sure that both values are null and
// bundle, we'll get back a null. So make sure that both values are null and
// both keys exist in the bundle.
return false;
} else if (valueOne instanceof boolean[]) {
@@ -538,8 +537,8 @@ public class GenericDocument {
/**
* Calculates the hash code for a bundle.
* <p> The hash code is only effected by the content in the bundle. Bundles will get
* consistent hash code if they have same content.
* <p> The hash code is only effected by the contents in the bundle. Bundles will get
* consistent hash code if they have same contents.
*/
@SuppressWarnings("unchecked")
private static int bundleHashCode(Bundle bundle) {
@@ -648,8 +647,11 @@ public class GenericDocument {
/**
* The builder class for {@link GenericDocument}.
*
* @param <BuilderType> Type of subclass who extend this.
* @param <BuilderType> Type of subclass who extends this.
*/
// This builder is specifically designed to be extended by classes deriving from
// GenericDocument.
@SuppressLint("StaticFinalBuilder")
public static class Builder<BuilderType extends Builder> {
private final Bundle mProperties = new Bundle();
@@ -662,12 +664,11 @@ public class GenericDocument {
*
* @param uri The uri of {@link GenericDocument}.
* @param schemaType The schema type of the {@link GenericDocument}. The passed-in
* {@code schemaType} must be defined using {@code AppSearchManager#setSchema} prior
* {@code schemaType} must be defined using {@link AppSearchSession#setSchema} prior
* to inserting a document of this {@code schemaType} into the AppSearch index using
* {@code AppSearchManager#putDocuments}. Otherwise, the document will be
* rejected by {@code AppSearchManager#putDocuments}.
* {@link AppSearchSession#putDocuments}. Otherwise, the document will be
* rejected by {@link AppSearchSession#putDocuments}.
*/
//TODO(b/157082794) Linkify AppSearchManager once that API is public.
@SuppressWarnings("unchecked")
public Builder(@NonNull String uri, @NonNull String schemaType) {
Preconditions.checkNotNull(uri);
@@ -685,9 +686,12 @@ public class GenericDocument {
}
/**
* Set the app-defined namespace this Document resides in. No special values are
* reserved or understood by the infrastructure. URIs are unique within a namespace. The
* number of namespaces per app should be kept small for efficiency reasons.
* Sets the app-defined namespace this Document resides in. No special values are
* reserved or understood by the infrastructure.
*
* <p>URIs are unique within a namespace.
*
* <p>The number of namespaces per app should be kept small for efficiency reasons.
*/
@NonNull
public BuilderType setNamespace(@NonNull String namespace) {
@@ -714,7 +718,7 @@ public class GenericDocument {
}
/**
* Set the creation timestamp in milliseconds of the {@link GenericDocument}. Should be
* Sets the creation timestamp of the {@link GenericDocument}, in milliseconds. Should be
* set using a value obtained from the {@link System#currentTimeMillis()} time base.
*/
@NonNull
@@ -726,7 +730,7 @@ public class GenericDocument {
}
/**
* Set the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
* Sets the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
*
* <p>After this many milliseconds since the {@link #setCreationTimestampMillis creation
* timestamp}, the document is deleted.
@@ -752,7 +756,7 @@ public class GenericDocument {
* @param values The {@code String} values of the property.
*/
@NonNull
public BuilderType setProperty(@NonNull String key, @NonNull String... values) {
public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
@@ -768,7 +772,7 @@ public class GenericDocument {
* @param values The {@code boolean} values of the property.
*/
@NonNull
public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) {
public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
@@ -784,7 +788,7 @@ public class GenericDocument {
* @param values The {@code long} values of the property.
*/
@NonNull
public BuilderType setProperty(@NonNull String key, @NonNull long... values) {
public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
@@ -800,7 +804,7 @@ public class GenericDocument {
* @param values The {@code double} values of the property.
*/
@NonNull
public BuilderType setProperty(@NonNull String key, @NonNull double... values) {
public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
@@ -815,7 +819,7 @@ public class GenericDocument {
* @param values The {@code byte[]} of the property.
*/
@NonNull
public BuilderType setProperty(@NonNull String key, @NonNull byte[]... values) {
public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);
@@ -831,7 +835,8 @@ public class GenericDocument {
* @param values The {@link GenericDocument} values of the property.
*/
@NonNull
public BuilderType setProperty(@NonNull String key, @NonNull GenericDocument... values) {
public BuilderType setPropertyDocument(
@NonNull String key, @NonNull GenericDocument... values) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(values);

View File

@@ -17,12 +17,12 @@
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;
import java.util.Set;
/**
@@ -40,18 +40,16 @@ public final class GetByUriRequest {
mUris = uris;
}
/** @hide */
/** Returns the namespace to get documents from. */
@NonNull
public String getNamespace() {
return mNamespace;
}
/** @hide */
/** Returns the URIs to get from the namespace. */
@NonNull
public Set<String> getUris() {
return mUris;
return Collections.unmodifiableSet(mUris);
}
/** Builder for {@link GetByUriRequest} objects. */
@@ -75,14 +73,14 @@ public final class GetByUriRequest {
/** Adds one or more URIs to the request. */
@NonNull
public Builder addUris(@NonNull String... uris) {
public Builder addUri(@NonNull String... uris) {
Preconditions.checkNotNull(uris);
return addUris(Arrays.asList(uris));
return addUri(Arrays.asList(uris));
}
/** Adds one or more URIs to the request. */
@NonNull
public Builder addUris(@NonNull Collection<String> uris) {
public Builder addUri(@NonNull Collection<String> uris) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(uris);
mUris.addAll(uris);

View File

@@ -16,13 +16,16 @@
package android.app.appsearch;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.NonNull;
import android.app.appsearch.exceptions.AppSearchException;
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;
/**
@@ -38,11 +41,10 @@ public final class PutDocumentsRequest {
mDocuments = documents;
}
/** @hide */
/** Returns the documents that are part of this request. */
@NonNull
public List<GenericDocument> getDocuments() {
return mDocuments;
return Collections.unmodifiableList(mDocuments);
}
/** Builder for {@link PutDocumentsRequest} objects. */
@@ -51,6 +53,7 @@ public final class PutDocumentsRequest {
private boolean mBuilt = false;
/** Adds one or more documents to the request. */
@SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
@NonNull
public Builder addGenericDocument(@NonNull GenericDocument... documents) {
Preconditions.checkNotNull(documents);
@@ -58,6 +61,7 @@ public final class PutDocumentsRequest {
}
/** Adds one or more documents to the request. */
@SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
@NonNull
public Builder addGenericDocument(@NonNull Collection<GenericDocument> documents) {
Preconditions.checkState(!mBuilt, "Builder has already been used");

View File

@@ -17,12 +17,12 @@
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;
import java.util.Set;
/**
@@ -40,18 +40,16 @@ public final class RemoveByUriRequest {
mUris = uris;
}
/** @hide */
/** Returns the namespace to remove documents from. */
@NonNull
public String getNamespace() {
return mNamespace;
}
/** @hide */
/** Returns the URIs to remove from the namespace. */
@NonNull
public Set<String> getUris() {
return mUris;
return Collections.unmodifiableSet(mUris);
}
/** Builder for {@link RemoveByUriRequest} objects. */
@@ -75,14 +73,14 @@ public final class RemoveByUriRequest {
/** Adds one or more URIs to the request. */
@NonNull
public Builder addUris(@NonNull String... uris) {
public Builder addUri(@NonNull String... uris) {
Preconditions.checkNotNull(uris);
return addUris(Arrays.asList(uris));
return addUri(Arrays.asList(uris));
}
/** Adds one or more URIs to the request. */
@NonNull
public Builder addUris(@NonNull Collection<String> uris) {
public Builder addUri(@NonNull Collection<String> uris) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(uris);
mUris.addAll(uris);

View File

@@ -49,19 +49,22 @@ public final class SearchResult {
@NonNull
private final Bundle mDocumentBundle;
/** Cache of the inflated document. Comes from inflating mDocumentBundle at first use. */
@Nullable
private GenericDocument mDocument;
@Nullable
private final List<Bundle> mMatchBundles;
/**
* Contains a list of Snippets that matched the request. Only populated when requested in
* both {@link SearchSpec.Builder#setSnippetCount(int)}
* and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}.
* Contains a list of MatchInfo bundles that matched the request.
*
* Only populated when requested in both {@link SearchSpec.Builder#setSnippetCount} and
* {@link SearchSpec.Builder#setSnippetCountPerProperty}.
*
* @see #getMatches()
*/
@NonNull
private final List<Bundle> mMatchBundles;
/** Cache of the inflated matches. Comes from inflating mMatchBundles at first use. */
@Nullable
private List<MatchInfo> mMatches;
@@ -70,7 +73,7 @@ public final class SearchResult {
public SearchResult(@NonNull Bundle bundle) {
mBundle = Preconditions.checkNotNull(bundle);
mDocumentBundle = Preconditions.checkNotNull(bundle.getBundle(DOCUMENT_FIELD));
mMatchBundles = bundle.getParcelableArrayList(MATCHES_FIELD);
mMatchBundles = Preconditions.checkNotNull(bundle.getParcelableArrayList(MATCHES_FIELD));
}
/** @hide */
@@ -93,19 +96,16 @@ public final class SearchResult {
}
/**
* Contains a list of Snippets that matched the request. Only populated when requested in
* both {@link SearchSpec.Builder#setSnippetCount(int)}
* and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}.
* Contains a list of Snippets that matched the request.
*
* @return List of matches based on {@link SearchSpec}, if snippeting is disabled and this
* method is called it will return {@code null}. Users can also restrict snippet population
* using {@link SearchSpec.Builder#setSnippetCount} and
* {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}, for all results after that
* value this method will return {@code null}.
* @return List of matches based on {@link SearchSpec}. If snippeting is disabled using
* {@link SearchSpec.Builder#setSnippetCount} or
* {@link SearchSpec.Builder#setSnippetCountPerProperty}, for all results after that
* value, this method returns an empty list.
*/
@Nullable
@NonNull
public List<MatchInfo> getMatches() {
if (mMatchBundles != null && mMatches == null) {
if (mMatches == null) {
mMatches = new ArrayList<>(mMatchBundles.size());
for (int i = 0; i < mMatchBundles.size(); i++) {
MatchInfo matchInfo = new MatchInfo(getDocument(), mMatchBundles.get(i));
@@ -119,8 +119,8 @@ public final class SearchResult {
* Snippet: It refers to a substring of text from the content of document that is returned as a
* part of search result.
* This class represents a match objects for any Snippets that might be present in
* {@link SearchResults} from query. Using this class user can get the full text, exact matches
* and Snippets of document content for a given match.
* {@link SearchResults} from query. Using this class
* user can get the full text, exact matches and Snippets of document content for a given match.
*
* <p>Class Example 1:
* A document contains following text in property subject:

View File

@@ -16,16 +16,23 @@
package android.app.appsearch;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.exceptions.IllegalSearchSpecException;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* This class represents the specification logic for AppSearch. It can be used to set the type of
@@ -34,69 +41,26 @@ import java.lang.annotation.RetentionPolicy;
*/
// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
public final class SearchSpec {
/** @hide */
public static final String TERM_MATCH_TYPE_FIELD = "termMatchType";
/** @hide */
public static final String SCHEMA_TYPES_FIELD = "schemaType";
/** @hide */
public static final String NAMESPACE_FIELD = "namespace";
/** @hide */
public static final String NUM_PER_PAGE_FIELD = "numPerPage";
/** @hide */
public static final String RANKING_STRATEGY_FIELD = "rankingStrategy";
/** @hide */
public static final String ORDER_FIELD = "order";
/** @hide */
public static final String SNIPPET_COUNT_FIELD = "snippetCount";
/** @hide */
public static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
/** @hide */
public static final String MAX_SNIPPET_FIELD = "maxSnippet";
static final String TERM_MATCH_TYPE_FIELD = "termMatchType";
static final String SCHEMA_TYPE_FIELD = "schemaType";
static final String NAMESPACE_FIELD = "namespace";
static final String NUM_PER_PAGE_FIELD = "numPerPage";
static final String RANKING_STRATEGY_FIELD = "rankingStrategy";
static final String ORDER_FIELD = "order";
static final String SNIPPET_COUNT_FIELD = "snippetCount";
static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
static final String MAX_SNIPPET_FIELD = "maxSnippet";
/** @hide */
public static final int DEFAULT_NUM_PER_PAGE = 10;
// TODO(b/170371356): In framework, we may want these limits might be flag controlled.
private static final int MAX_NUM_PER_PAGE = 10_000;
private static final int MAX_SNIPPET_COUNT = 10_000;
private static final int MAX_SNIPPET_PER_PROPERTY_COUNT = 10_000;
private static final int MAX_SNIPPET_SIZE_LIMIT = 10_000;
private final Bundle mBundle;
/** @hide */
public SearchSpec(@NonNull Bundle bundle) {
Preconditions.checkNotNull(bundle);
mBundle = bundle;
}
/**
* Returns the {@link Bundle} populated by this builder.
* @hide
*/
@NonNull
public Bundle getBundle() {
return mBundle;
}
/**
* Term Match Type for the query.
* @hide
@@ -108,7 +72,7 @@ public final class SearchSpec {
TERM_MATCH_PREFIX
})
@Retention(RetentionPolicy.SOURCE)
public @interface TermMatchCode {}
public @interface TermMatch {}
/**
* Query terms will only match exact tokens in the index.
@@ -126,14 +90,14 @@ public final class SearchSpec {
* @hide
*/
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link ScoringSpecProto.RankingStrategy.Code }
// {@link ScoringSpecProto.RankingStrategy.Code}
@IntDef(value = {
RANKING_STRATEGY_NONE,
RANKING_STRATEGY_DOCUMENT_SCORE,
RANKING_STRATEGY_CREATION_TIMESTAMP
})
@Retention(RetentionPolicy.SOURCE)
public @interface RankingStrategyCode {}
public @interface RankingStrategy {}
/** No Ranking, results are returned in arbitrary order.*/
public static final int RANKING_STRATEGY_NONE = 0;
@@ -147,23 +111,109 @@ public final class SearchSpec {
* @hide
*/
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link ScoringSpecProto.Order.Code }
// {@link ScoringSpecProto.Order.Code}
@IntDef(value = {
ORDER_DESCENDING,
ORDER_ASCENDING
})
@Retention(RetentionPolicy.SOURCE)
public @interface OrderCode {}
public @interface Order {}
/** Search results will be returned in a descending order. */
public static final int ORDER_DESCENDING = 0;
/** Search results will be returned in an ascending order. */
public static final int ORDER_ASCENDING = 1;
private final Bundle mBundle;
/** @hide */
public SearchSpec(@NonNull Bundle bundle) {
Preconditions.checkNotNull(bundle);
mBundle = bundle;
}
/**
* Returns the {@link Bundle} populated by this builder.
* @hide
*/
@NonNull
public Bundle getBundle() {
return mBundle;
}
/** Returns how the query terms should match terms in the index. */
public @TermMatch int getTermMatch() {
return mBundle.getInt(TERM_MATCH_TYPE_FIELD, -1);
}
/**
* Returns the list of schema types to search for.
*
* <p>If empty, the query will search over all schema types.
*/
@NonNull
public List<String> getSchemas() {
List<String> schemas = mBundle.getStringArrayList(SCHEMA_TYPE_FIELD);
if (schemas == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(schemas);
}
/**
* Returns the list of namespaces to search for.
*
* <p>If empty, the query will search over all namespaces.
*/
@NonNull
public List<String> getNamespaces() {
List<String> namespaces = mBundle.getStringArrayList(NAMESPACE_FIELD);
if (namespaces == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(namespaces);
}
/** Returns the number of results per page in the returned object. */
public int getNumPerPage() {
return mBundle.getInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE);
}
/** Returns the ranking strategy. */
public @RankingStrategy int getRankingStrategy() {
return mBundle.getInt(RANKING_STRATEGY_FIELD);
}
/** Returns the order of returned search results (descending or ascending). */
public @Order int getOrder() {
return mBundle.getInt(ORDER_FIELD);
}
/** Returns how many documents to generate snippets for. */
public int getSnippetCount() {
return mBundle.getInt(SNIPPET_COUNT_FIELD);
}
/**
* Returns how many matches for each property of a matching document to generate snippets for.
*/
public int getSnippetCountPerProperty() {
return mBundle.getInt(SNIPPET_COUNT_PER_PROPERTY_FIELD);
}
/** Returns the maximum size of a snippet in characters. */
public int getMaxSnippetSize() {
return mBundle.getInt(MAX_SNIPPET_FIELD);
}
/** Builder for {@link SearchSpec objects}. */
public static final class Builder {
private final Bundle mBundle;
private final ArrayList<String> mSchemaTypes = new ArrayList<>();
private final ArrayList<String> mNamespaces = new ArrayList<>();
private boolean mBuilt = false;
/** Creates a new {@link SearchSpec.Builder}. */
@@ -176,7 +226,7 @@ public final class SearchSpec {
* Indicates how the query terms should match {@code TermMatchCode} in the index.
*/
@NonNull
public Builder setTermMatch(@TermMatchCode int termMatchTypeCode) {
public Builder setTermMatch(@TermMatch int termMatchTypeCode) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_EXACT_ONLY,
TERM_MATCH_PREFIX, "Term match type");
@@ -187,13 +237,27 @@ public final class SearchSpec {
/**
* Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that
* have the specified schema types.
*
* <p>If unset, the query will search over all schema types.
*/
@NonNull
public Builder setSchemaTypes(@NonNull String... schemaTypes) {
public Builder addSchema(@NonNull String... schemaTypes) {
Preconditions.checkNotNull(schemaTypes);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBundle.putStringArray(SCHEMA_TYPES_FIELD, schemaTypes);
return addSchema(Arrays.asList(schemaTypes));
}
/**
* Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that
* have the specified schema types.
*
* <p>If unset, the query will search over all schema types.
*/
@NonNull
public Builder addSchema(@NonNull Collection<String> schemaTypes) {
Preconditions.checkNotNull(schemaTypes);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mSchemaTypes.addAll(schemaTypes);
return this;
}
@@ -203,10 +267,22 @@ public final class SearchSpec {
* <p>If unset, the query will search over all namespaces.
*/
@NonNull
public Builder setNamespaces(@NonNull String... namespaces) {
public Builder addNamespace(@NonNull String... namespaces) {
Preconditions.checkNotNull(namespaces);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBundle.putStringArray(NAMESPACE_FIELD, namespaces);
return addNamespace(Arrays.asList(namespaces));
}
/**
* Adds a namespace filter to {@link SearchSpec} Entry. Only search for documents that
* have the specified namespaces.
* <p>If unset, the query will search over all namespaces.
*/
@NonNull
public Builder addNamespace(@NonNull Collection<String> namespaces) {
Preconditions.checkNotNull(namespaces);
Preconditions.checkState(!mBuilt, "Builder has already been used");
mNamespaces.addAll(namespaces);
return this;
}
@@ -224,7 +300,7 @@ public final class SearchSpec {
/** Sets ranking strategy for AppSearch results.*/
@NonNull
public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) {
public Builder setRankingStrategy(@RankingStrategy int rankingStrategy) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(rankingStrategy, RANKING_STRATEGY_NONE,
RANKING_STRATEGY_CREATION_TIMESTAMP, "Result ranking strategy");
@@ -238,7 +314,7 @@ public final class SearchSpec {
* <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}.
*/
@NonNull
public Builder setOrder(@OrderCode int order) {
public Builder setOrder(@Order int order) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkArgumentInRange(order, ORDER_DESCENDING, ORDER_ASCENDING,
"Result ranking order");
@@ -264,11 +340,12 @@ public final class SearchSpec {
}
/**
* Only the first {@code matchesCountPerProperty} matches for a every property of
* {@link GenericDocument} will contain snippet information.
* Sets {@code snippetCountPerProperty}. Only the first {@code snippetCountPerProperty}
* snippets for a every property of {@link GenericDocument} will contain snippet
* information.
*
* <p>If set to 0, snippeting is disabled and {@link SearchResult#getMatches} will return
* {@code null} for that result.
* <p>If set to 0, snippeting is disabled and {@link SearchResult#getMatches}
* will return {@code null} for that result.
*
* <p>The value should be set in range[0, 10k].
*/
@@ -286,10 +363,13 @@ public final class SearchSpec {
* {@code maxSnippetSize/2} bytes before the middle of the matching token and end at
* {@code maxSnippetSize/2} bytes after the middle of the matching token. It respects
* token boundaries, therefore the returned window may be smaller than requested.
*
* <p> Setting {@code maxSnippetSize} to 0 will disable windowing and an empty string will
* be returned. If matches enabled is also set to false, then snippeting is disabled.
*
* <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
* return a window of "bar baz bat" which is only 11 bytes long.
*
* <p>The value should be in range[0, 10k].
*/
@NonNull
@@ -312,6 +392,8 @@ public final class SearchSpec {
if (!mBundle.containsKey(TERM_MATCH_TYPE_FIELD)) {
throw new IllegalSearchSpecException("Missing termMatchType field.");
}
mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
mBundle.putStringArrayList(SCHEMA_TYPE_FIELD, mSchemaTypes);
mBuilt = true;
return new SearchSpec(mBundle);
}

View File

@@ -16,13 +16,17 @@
package android.app.appsearch;
import android.annotation.NonNull;
import android.util.ArraySet;
import android.annotation.SuppressLint;
import android.annotation.NonNull;
import android.app.appsearch.exceptions.AppSearchException;
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.List;
import java.util.Set;
/**
@@ -40,15 +44,13 @@ public final class SetSchemaRequest {
mForceOverride = forceOverride;
}
/** @hide */
/** Returns the schemas that are part of this request. */
@NonNull
public Set<AppSearchSchema> getSchemas() {
return mSchemas;
}
/** @hide */
/** Returns whether this request will force the schema to be overridden. */
public boolean isForceOverride() {
return mForceOverride;
}

View File

@@ -54,6 +54,7 @@ public class AppSearchException extends Exception {
mResultCode = resultCode;
}
/** Returns the result code this exception was constructed with. */
public @AppSearchResult.ResultCode int getResultCode() {
return mResultCode;
}

View File

@@ -33,11 +33,11 @@ import android.os.UserHandle;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localbackend.AppSearchImpl;
import com.android.server.appsearch.external.localbackend.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.external.localbackend.converter.SchemaToProtoConverter;
import com.android.server.appsearch.external.localbackend.converter.SearchResultToProtoConverter;
import com.android.server.appsearch.external.localbackend.converter.SearchSpecToProtoConverter;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
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.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.SchemaProto;
@@ -46,6 +46,7 @@ import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchSpecProto;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
@@ -193,7 +194,12 @@ public class AppSearchManagerService extends SystemService {
SearchSpecToProtoConverter.toResultSpecProto(searchSpec),
SearchSpecToProtoConverter.toScoringSpecProto(searchSpec));
List<SearchResult> searchResultList =
SearchResultToProtoConverter.convert(searchResultProto);
new ArrayList<>(searchResultProto.getResultsCount());
for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
SearchResult result = SearchResultToProtoConverter.convertSearchResult(
searchResultProto.getResults(i));
searchResultList.add(result);
}
SearchResults searchResults =
new SearchResults(searchResultList, searchResultProto.getNextPageToken());
callback.complete(AppSearchResult.newSuccessfulResult(searchResults));

View File

@@ -24,7 +24,7 @@ import android.os.Environment;
import android.os.storage.StorageManager;
import android.util.SparseArray;
import com.android.server.appsearch.external.localbackend.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import java.io.File;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend;
package com.android.server.appsearch.external.localstorage;
import android.util.Log;

View File

@@ -14,9 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
import android.os.Bundle;
package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
@@ -43,7 +41,6 @@ public final class GenericDocumentToProtoConverter {
@SuppressWarnings("unchecked")
public static DocumentProto convert(@NonNull GenericDocument document) {
Preconditions.checkNotNull(document);
Bundle properties = document.getBundle().getBundle(GenericDocument.PROPERTIES_FIELD);
DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
mProtoBuilder.setUri(document.getUri())
.setSchema(document.getSchemaType())
@@ -51,42 +48,45 @@ public final class GenericDocumentToProtoConverter {
.setScore(document.getScore())
.setTtlMs(document.getTtlMillis())
.setCreationTimestampMs(document.getCreationTimestampMillis());
ArrayList<String> keys = new ArrayList<>(properties.keySet());
ArrayList<String> keys = new ArrayList<>(document.getPropertyNames());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i++) {
String name = keys.get(i);
Object values = properties.get(name);
PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
if (values instanceof boolean[]) {
for (boolean value : (boolean[]) values) {
propertyProto.addBooleanValues(value);
String[] stringValues = document.getPropertyStringArray(name);
long[] longValues = document.getPropertyLongArray(name);
double[] doubleValues = document.getPropertyDoubleArray(name);
boolean[] booleanValues = document.getPropertyBooleanArray(name);
byte[][] bytesValues = document.getPropertyBytesArray(name);
GenericDocument[] documentValues = document.getPropertyDocumentArray(name);
if (stringValues != null) {
for (int j = 0; j < stringValues.length; j++) {
propertyProto.addStringValues(stringValues[j]);
}
} else if (values instanceof long[]) {
for (long value : (long[]) values) {
propertyProto.addInt64Values(value);
} else if (longValues != null) {
for (int j = 0; j < longValues.length; j++) {
propertyProto.addInt64Values(longValues[j]);
}
} else if (values instanceof double[]) {
for (double value : (double[]) values) {
propertyProto.addDoubleValues(value);
} else if (doubleValues != null) {
for (int j = 0; j < doubleValues.length; j++) {
propertyProto.addDoubleValues(doubleValues[j]);
}
} else if (values instanceof String[]) {
for (String value : (String[]) values) {
propertyProto.addStringValues(value);
} else if (booleanValues != null) {
for (int j = 0; j < booleanValues.length; j++) {
propertyProto.addBooleanValues(booleanValues[j]);
}
} else if (values instanceof ArrayList) {
for (Bundle bundle : (ArrayList<Bundle>) values) {
byte[] value = bundle.getByteArray(GenericDocument.BYTE_ARRAY_FIELD);
propertyProto.addBytesValues(ByteString.copyFrom(value));
} else if (bytesValues != null) {
for (int j = 0; j < bytesValues.length; j++) {
propertyProto.addBytesValues(ByteString.copyFrom(bytesValues[j]));
}
} else if (values instanceof Bundle[]) {
for (Bundle bundle : (Bundle[]) values) {
GenericDocument value = new GenericDocument(bundle);
propertyProto.addDocumentValues(convert(value));
} else if (documentValues != null) {
for (int j = 0; j < documentValues.length; j++) {
DocumentProto proto = convert(documentValues[j]);
propertyProto.addDocumentValues(proto);
}
} else {
throw new IllegalStateException(
"Property \"" + name + "\" has unsupported value type \""
+ values.getClass().getSimpleName() + "\"");
"Property \"" + name + "\" has unsupported value type");
}
mProtoBuilder.addProperties(propertyProto);
}
@@ -107,42 +107,42 @@ public final class GenericDocumentToProtoConverter {
for (int i = 0; i < proto.getPropertiesCount(); i++) {
PropertyProto property = proto.getProperties(i);
String name = property.getName();
if (property.getBooleanValuesCount() > 0) {
boolean[] values = new boolean[property.getBooleanValuesCount()];
if (property.getStringValuesCount() > 0) {
String[] values = new String[property.getStringValuesCount()];
for (int j = 0; j < values.length; j++) {
values[j] = property.getBooleanValues(j);
values[j] = property.getStringValues(j);
}
documentBuilder.setProperty(name, values);
documentBuilder.setPropertyString(name, values);
} else if (property.getInt64ValuesCount() > 0) {
long[] values = new long[property.getInt64ValuesCount()];
for (int j = 0; j < values.length; j++) {
values[j] = property.getInt64Values(j);
}
documentBuilder.setProperty(name, values);
documentBuilder.setPropertyLong(name, values);
} else if (property.getDoubleValuesCount() > 0) {
double[] values = new double[property.getDoubleValuesCount()];
for (int j = 0; j < values.length; j++) {
values[j] = property.getDoubleValues(j);
}
documentBuilder.setProperty(name, values);
} else if (property.getStringValuesCount() > 0) {
String[] values = new String[property.getStringValuesCount()];
documentBuilder.setPropertyDouble(name, values);
} else if (property.getBooleanValuesCount() > 0) {
boolean[] values = new boolean[property.getBooleanValuesCount()];
for (int j = 0; j < values.length; j++) {
values[j] = property.getStringValues(j);
values[j] = property.getBooleanValues(j);
}
documentBuilder.setProperty(name, values);
documentBuilder.setPropertyBoolean(name, values);
} else if (property.getBytesValuesCount() > 0) {
byte[][] values = new byte[property.getBytesValuesCount()][];
for (int j = 0; j < values.length; j++) {
values[j] = property.getBytesValues(j).toByteArray();
}
documentBuilder.setProperty(name, values);
documentBuilder.setPropertyBytes(name, values);
} else if (property.getDocumentValuesCount() > 0) {
GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()];
for (int j = 0; j < values.length; j++) {
values[j] = convert(property.getDocumentValues(j));
}
documentBuilder.setProperty(name, values);
documentBuilder.setPropertyDocument(name, values);
} else {
throw new IllegalStateException("Unknown type of value: " + name);
}

View File

@@ -14,9 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
import android.os.Bundle;
package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
@@ -28,7 +26,7 @@ import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.TermMatchType;
import java.util.ArrayList;
import java.util.List;
/**
* Translates an {@link AppSearchSchema} into a {@link SchemaTypeConfigProto}.
@@ -45,31 +43,26 @@ public final class SchemaToProtoConverter {
@NonNull
public static SchemaTypeConfigProto convert(@NonNull AppSearchSchema schema) {
Preconditions.checkNotNull(schema);
Bundle bundle = schema.getBundle();
SchemaTypeConfigProto.Builder protoBuilder =
SchemaTypeConfigProto.newBuilder()
.setSchemaType(bundle.getString(AppSearchSchema.SCHEMA_TYPE_FIELD, ""));
ArrayList<Bundle> properties =
bundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD);
if (properties != null) {
for (int i = 0; i < properties.size(); i++) {
PropertyConfigProto propertyProto = convertProperty(properties.get(i));
protoBuilder.addProperties(propertyProto);
}
SchemaTypeConfigProto.newBuilder().setSchemaType(schema.getSchemaTypeName());
List<AppSearchSchema.PropertyConfig> properties = schema.getProperties();
for (int i = 0; i < properties.size(); i++) {
PropertyConfigProto propertyProto = convertProperty(properties.get(i));
protoBuilder.addProperties(propertyProto);
}
return protoBuilder.build();
}
@NonNull
private static PropertyConfigProto convertProperty(@NonNull Bundle bundle) {
Preconditions.checkNotNull(bundle);
private static PropertyConfigProto convertProperty(
@NonNull AppSearchSchema.PropertyConfig property) {
Preconditions.checkNotNull(property);
PropertyConfigProto.Builder propertyConfigProto = PropertyConfigProto.newBuilder()
.setPropertyName(bundle.getString(AppSearchSchema.PropertyConfig.NAME_FIELD, ""));
.setPropertyName(property.getName());
IndexingConfig.Builder indexingConfig = IndexingConfig.newBuilder();
// Set dataType
@AppSearchSchema.PropertyConfig.DataType int dataType =
bundle.getInt(AppSearchSchema.PropertyConfig.DATA_TYPE_FIELD);
@AppSearchSchema.PropertyConfig.DataType int dataType = property.getDataType();
PropertyConfigProto.DataType.Code dataTypeProto =
PropertyConfigProto.DataType.Code.forNumber(dataType);
if (dataTypeProto == null) {
@@ -78,12 +71,13 @@ public final class SchemaToProtoConverter {
propertyConfigProto.setDataType(dataTypeProto);
// Set schemaType
propertyConfigProto.setSchemaType(
bundle.getString(AppSearchSchema.PropertyConfig.SCHEMA_TYPE_FIELD, ""));
String schemaType = property.getSchemaType();
if (schemaType != null) {
propertyConfigProto.setSchemaType(schemaType);
}
// Set cardinality
@AppSearchSchema.PropertyConfig.Cardinality int cardinality =
bundle.getInt(AppSearchSchema.PropertyConfig.CARDINALITY_FIELD);
@AppSearchSchema.PropertyConfig.Cardinality int cardinality = property.getCardinality();
PropertyConfigProto.Cardinality.Code cardinalityProto =
PropertyConfigProto.Cardinality.Code.forNumber(cardinality);
if (cardinalityProto == null) {
@@ -92,8 +86,7 @@ public final class SchemaToProtoConverter {
propertyConfigProto.setCardinality(cardinalityProto);
// Set indexingType
@AppSearchSchema.PropertyConfig.IndexingType int indexingType =
bundle.getInt(AppSearchSchema.PropertyConfig.INDEXING_TYPE_FIELD);
@AppSearchSchema.PropertyConfig.IndexingType int indexingType = property.getIndexingType();
TermMatchType.Code termMatchTypeProto;
switch (indexingType) {
case AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE:
@@ -112,7 +105,7 @@ public final class SchemaToProtoConverter {
// Set tokenizerType
@AppSearchSchema.PropertyConfig.TokenizerType int tokenizerType =
bundle.getInt(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_FIELD);
property.getTokenizerType();
IndexingConfig.TokenizerType.Code tokenizerTypeProto =
IndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
if (tokenizerTypeProto == null) {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
package com.android.server.appsearch.external.localstorage.converter;
import android.os.Bundle;
@@ -22,43 +22,32 @@ import android.annotation.NonNull;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResults;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SnippetMatchProto;
import com.google.android.icing.proto.SnippetProto;
import java.util.ArrayList;
import java.util.List;
/**
* Translates a {@link SearchResultProto} into {@link SearchResults}.
* Translates a {@link SearchResultProto} into {@link SearchResult}s.
*
* @hide
*/
public class SearchResultToProtoConverter {
private SearchResultToProtoConverter() {}
/** Translates a {@link SearchResultProto} into a list of {@link SearchResult}. */
@NonNull
public static List<SearchResult> convert(@NonNull SearchResultProto searchResultProto) {
List<SearchResult> results = new ArrayList<>(searchResultProto.getResultsCount());
for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
results.add(convertSearchResult(searchResultProto.getResults(i)));
}
return results;
}
/** Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}. */
@NonNull
static SearchResult convertSearchResult(@NonNull SearchResultProto.ResultProto proto) {
public static SearchResult convertSearchResult(
@NonNull SearchResultProto.ResultProtoOrBuilder proto) {
Bundle bundle = new Bundle();
GenericDocument document = GenericDocumentToProtoConverter.convert(proto.getDocument());
bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle());
ArrayList<Bundle> matchList = null;
ArrayList<Bundle> matchList = new ArrayList<>();
if (proto.hasSnippet()) {
matchList = new ArrayList<>();
for (int i = 0; i < proto.getSnippet().getEntriesCount(); i++) {
SnippetProto.EntryProto entry = proto.getSnippet().getEntries(i);
for (int j = 0; j < entry.getSnippetMatchesCount(); j++) {

View File

@@ -14,9 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
import android.os.Bundle;
package com.android.server.appsearch.external.localstorage.converter;
import android.annotation.NonNull;
@@ -28,8 +26,6 @@ import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.TermMatchType;
import java.util.Arrays;
/**
* Translates a {@link SearchSpec} into icing search protos.
* @hide
@@ -42,25 +38,17 @@ public final class SearchSpecToProtoConverter {
@NonNull
public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
Bundle bundle = spec.getBundle();
SearchSpecProto.Builder protoBuilder = SearchSpecProto.newBuilder();
SearchSpecProto.Builder protoBuilder = SearchSpecProto.newBuilder()
.addAllSchemaTypeFilters(spec.getSchemas())
.addAllNamespaceFilters(spec.getNamespaces());
@SearchSpec.TermMatchCode int termMatchCode =
bundle.getInt(SearchSpec.TERM_MATCH_TYPE_FIELD);
@SearchSpec.TermMatch int termMatchCode = spec.getTermMatch();
TermMatchType.Code termMatchCodeProto = TermMatchType.Code.forNumber(termMatchCode);
if (termMatchCodeProto == null || termMatchCodeProto.equals(TermMatchType.Code.UNKNOWN)) {
throw new IllegalArgumentException("Invalid term match type: " + termMatchCode);
}
protoBuilder.setTermMatchType(termMatchCodeProto);
String[] schemaTypes = bundle.getStringArray(SearchSpec.SCHEMA_TYPES_FIELD);
if (schemaTypes != null) {
protoBuilder.addAllSchemaTypeFilters(Arrays.asList(schemaTypes));
}
String[] namespaces = bundle.getStringArray(SearchSpec.NAMESPACE_FIELD);
if (namespaces != null) {
protoBuilder.addAllNamespaceFilters(Arrays.asList(namespaces));
}
return protoBuilder.build();
}
@@ -68,27 +56,23 @@ public final class SearchSpecToProtoConverter {
@NonNull
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
Bundle bundle = spec.getBundle();
return ResultSpecProto.newBuilder()
.setNumPerPage(bundle.getInt(
SearchSpec.NUM_PER_PAGE_FIELD, SearchSpec.DEFAULT_NUM_PER_PAGE))
.setSnippetSpec(ResultSpecProto.SnippetSpecProto.newBuilder()
.setNumToSnippet(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD))
.setNumMatchesPerProperty(
bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD))
.setMaxWindowBytes(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)))
.setNumPerPage(spec.getNumPerPage())
.setSnippetSpec(
ResultSpecProto.SnippetSpecProto.newBuilder()
.setNumToSnippet(spec.getSnippetCount())
.setNumMatchesPerProperty(spec.getSnippetCountPerProperty())
.setMaxWindowBytes(spec.getMaxSnippetSize()))
.build();
}
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
@NonNull
public static ScoringSpecProto toScoringSpecProto(@NonNull SearchSpec spec) {
Preconditions.checkNotNull(spec);
Bundle bundle = spec.getBundle();
ScoringSpecProto.Builder protoBuilder = ScoringSpecProto.newBuilder();
@SearchSpec.OrderCode int orderCode = bundle.getInt(SearchSpec.ORDER_FIELD);
@SearchSpec.Order int orderCode = spec.getOrder();
ScoringSpecProto.Order.Code orderCodeProto =
ScoringSpecProto.Order.Code.forNumber(orderCode);
if (orderCodeProto == null) {
@@ -96,8 +80,7 @@ public final class SearchSpecToProtoConverter {
}
protoBuilder.setOrderBy(orderCodeProto);
@SearchSpec.RankingStrategyCode int rankingStrategyCode =
bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD);
@SearchSpec.RankingStrategy int rankingStrategyCode = spec.getRankingStrategy();
ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto =
ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategyCode);
if (rankingStrategyCodeProto == null) {

View File

@@ -30,7 +30,7 @@ public class AppSearchEmailTest {
// Score and Property are mixed into the middle to make sure DocumentBuilder's
// methods can be interleaved with EmailBuilder's methods.
.setScore(1)
.setProperty("propertyKey", "propertyValue1", "propertyValue2")
.setPropertyString("propertyKey", "propertyValue1", "propertyValue2")
.setSubject("subject")
.setBody("EmailBody")
.build();

View File

@@ -39,22 +39,22 @@ public class GenericDocumentTest {
GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setTtlMillis(1L)
.setProperty("longKey1", 1L, 2L, 3L)
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("booleanKey1", true, false, true)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.build();
GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setTtlMillis(1L)
.setProperty("longKey1", 1L, 2L, 3L)
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("booleanKey1", true, false, true)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.build();
assertThat(document1).isEqualTo(document2);
assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
@@ -64,23 +64,23 @@ public class GenericDocumentTest {
public void testDocumentEquals_DifferentOrder() {
GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("longKey1", 1L, 2L, 3L)
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("booleanKey1", true, false, true)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyLong("longKey1", 1L, 2L, 3L)
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.build();
// Create second document with same parameter but different order.
GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("booleanKey1", true, false, true)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("longKey1", 1L, 2L, 3L)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.build();
assertThat(document1).isEqualTo(document2);
assertThat(document1.hashCode()).isEqualTo(document2.hashCode());
@@ -90,13 +90,13 @@ public class GenericDocumentTest {
public void testDocumentEquals_Failure() {
GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("longKey1", 1L, 2L, 3L)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.build();
// Create second document with same order but different value.
GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("longKey1", 1L, 2L, 4L) // Different
.setPropertyLong("longKey1", 1L, 2L, 4L) // Different
.build();
assertThat(document1).isNotEqualTo(document2);
assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
@@ -106,13 +106,13 @@ public class GenericDocumentTest {
public void testDocumentEquals_Failure_RepeatedFieldOrder() {
GenericDocument document1 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("booleanKey1", true, false, true)
.setPropertyBoolean("booleanKey1", true, false, true)
.build();
// Create second document with same order but different value.
GenericDocument document2 = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("booleanKey1", true, true, false) // Different
.setPropertyBoolean("booleanKey1", true, true, false) // Different
.build();
assertThat(document1).isNotEqualTo(document2);
assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode());
@@ -124,12 +124,12 @@ public class GenericDocumentTest {
.setCreationTimestampMillis(5L)
.setScore(1)
.setTtlMillis(1L)
.setProperty("longKey1", 1L)
.setProperty("doubleKey1", 1.0)
.setProperty("booleanKey1", true)
.setProperty("stringKey1", "test-value1")
.setProperty("byteKey1", sByteArray1)
.setProperty("documentKey1", sDocumentProperties1)
.setPropertyLong("longKey1", 1L)
.setPropertyDouble("doubleKey1", 1.0)
.setPropertyBoolean("booleanKey1", true)
.setPropertyString("stringKey1", "test-value1")
.setPropertyBytes("byteKey1", sByteArray1)
.setPropertyDocument("documentKey1", sDocumentProperties1)
.build();
assertThat(document.getUri()).isEqualTo("uri1");
assertThat(document.getTtlMillis()).isEqualTo(1L);
@@ -149,12 +149,12 @@ public class GenericDocumentTest {
public void testDocumentGetArrayValues() {
GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("longKey1", 1L, 2L, 3L)
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("booleanKey1", true, false, true)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.build();
assertThat(document.getUri()).isEqualTo("uri1");
@@ -176,12 +176,12 @@ public class GenericDocumentTest {
public void testDocument_ToString() throws Exception {
GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
.setCreationTimestampMillis(5L)
.setProperty("longKey1", 1L, 2L, 3L)
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("booleanKey1", true, false, true)
.setProperty("stringKey1", "String1", "String2", "String3")
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyString("stringKey1", "String1", "String2", "String3")
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.build();
String exceptedString = "{ key: 'creationTimestampMillis' value: 5 } "
+ "{ key: 'namespace' value: } "
@@ -219,9 +219,9 @@ public class GenericDocumentTest {
public void testDocumentGetValues_DifferentTypes() {
GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
.setScore(1)
.setProperty("longKey1", 1L)
.setProperty("booleanKey1", true, false, true)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyLong("longKey1", 1L)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.build();
// Get a value for a key that doesn't exist
@@ -246,6 +246,7 @@ public class GenericDocumentTest {
public void testDocumentInvalid() {
GenericDocument.Builder builder = new GenericDocument.Builder("uri1", "schemaType1");
expectThrows(
IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{}));
IllegalArgumentException.class,
() -> builder.setPropertyBoolean("test", new boolean[]{}));
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2020 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 org.testng.Assert.expectThrows;
import org.junit.Test;
public class SearchResultsTest {
@Test
public void buildSearchSpecWithoutTermMatchType() {
expectThrows(RuntimeException.class, () -> new SearchSpec.Builder()
.setSchemaTypes("testSchemaType")
.build());
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2020 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 static org.testng.Assert.expectThrows;
import android.os.Bundle;
import org.junit.Test;
public class SearchSpecTest {
@Test
public void buildSearchSpecWithoutTermMatchType() {
expectThrows(RuntimeException.class, () -> new SearchSpec.Builder()
.addSchema("testSchemaType")
.build());
}
@Test
public void testBuildSearchSpec() {
SearchSpec searchSpec = new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.addNamespace("namespace1", "namespace2")
.addSchema("schemaTypes1", "schemaTypes2")
.setSnippetCount(5)
.setSnippetCountPerProperty(10)
.setMaxSnippetSize(15)
.setNumPerPage(42)
.setOrder(SearchSpec.ORDER_ASCENDING)
.setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE)
.build();
assertThat(searchSpec.getTermMatch()).isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
assertThat(searchSpec.getNamespaces())
.containsExactly("namespace1", "namespace2").inOrder();
assertThat(searchSpec.getSchemas())
.containsExactly("schemaTypes1", "schemaTypes2").inOrder();
assertThat(searchSpec.getSnippetCount()).isEqualTo(5);
assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10);
assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15);
assertThat(searchSpec.getNumPerPage()).isEqualTo(42);
assertThat(searchSpec.getOrder()).isEqualTo(SearchSpec.ORDER_ASCENDING);
assertThat(searchSpec.getRankingStrategy())
.isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
}
@Test
public void testGetBundle() {
SearchSpec searchSpec = new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.addNamespace("namespace1", "namespace2")
.addSchema("schemaTypes1", "schemaTypes2")
.setSnippetCount(5)
.setSnippetCountPerProperty(10)
.setMaxSnippetSize(15)
.setNumPerPage(42)
.setOrder(SearchSpec.ORDER_ASCENDING)
.setRankingStrategy(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE)
.build();
Bundle bundle = searchSpec.getBundle();
assertThat(bundle.getInt(SearchSpec.TERM_MATCH_TYPE_FIELD))
.isEqualTo(SearchSpec.TERM_MATCH_PREFIX);
assertThat(bundle.getStringArrayList(SearchSpec.NAMESPACE_FIELD)).containsExactly(
"namespace1", "namespace2");
assertThat(bundle.getStringArrayList(SearchSpec.SCHEMA_TYPE_FIELD)).containsExactly(
"schemaTypes1", "schemaTypes2");
assertThat(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD)).isEqualTo(5);
assertThat(bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD)).isEqualTo(10);
assertThat(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)).isEqualTo(15);
assertThat(bundle.getInt(SearchSpec.NUM_PER_PAGE_FIELD)).isEqualTo(42);
assertThat(bundle.getInt(SearchSpec.ORDER_FIELD)).isEqualTo(SearchSpec.ORDER_ASCENDING);
assertThat(bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD))
.isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
}
}

View File

@@ -46,12 +46,12 @@ public class CustomerDocumentTest {
CustomerDocument customerDocument = new CustomerDocument.Builder("uri1")
.setScore(1)
.setCreationTimestampMillis(0)
.setProperty("longKey1", 1L, 2L, 3L)
.setProperty("doubleKey1", 1.0, 2.0, 3.0)
.setProperty("booleanKey1", true, false, true)
.setProperty("stringKey1", "test-value1", "test-value2", "test-value3")
.setProperty("byteKey1", sByteArray1, sByteArray2)
.setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
.setPropertyLong("longKey1", 1L, 2L, 3L)
.setPropertyDouble("doubleKey1", 1.0, 2.0, 3.0)
.setPropertyBoolean("booleanKey1", true, false, true)
.setPropertyString("stringKey1", "test-value1", "test-value2", "test-value3")
.setPropertyBytes("byteKey1", sByteArray1, sByteArray2)
.setPropertyDocument("documentKey1", sDocumentProperties1, sDocumentProperties2)
.build();
assertThat(customerDocument.getUri()).isEqualTo("uri1");

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend;
package com.android.server.appsearch.external.localstorage;
import static com.google.common.truth.Truth.assertThat;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
package com.android.server.appsearch.external.localstorage.converter;
import static com.google.common.truth.Truth.assertThat;
@@ -53,13 +53,13 @@ public class GenericDocumentToProtoConverterTest {
.setScore(1)
.setTtlMillis(1L)
.setNamespace("namespace")
.setProperty("longKey1", 1L)
.setProperty("doubleKey1", 1.0)
.setProperty("booleanKey1", true)
.setProperty("stringKey1", "test-value1")
.setProperty("byteKey1", BYTE_ARRAY_1, BYTE_ARRAY_2)
.setProperty("documentKey1", DOCUMENT_PROPERTIES_1)
.setProperty(GenericDocument.PROPERTIES_FIELD, DOCUMENT_PROPERTIES_2)
.setPropertyLong("longKey1", 1L)
.setPropertyDouble("doubleKey1", 1.0)
.setPropertyBoolean("booleanKey1", true)
.setPropertyString("stringKey1", "test-value1")
.setPropertyBytes("byteKey1", BYTE_ARRAY_1, BYTE_ARRAY_2)
.setPropertyDocument("documentKey1", DOCUMENT_PROPERTIES_1)
.setPropertyDocument("documentKey2", DOCUMENT_PROPERTIES_2)
.build();
// Create the Document proto. Need to sort the property order by key.
@@ -87,8 +87,8 @@ public class GenericDocumentToProtoConverterTest {
PropertyProto.newBuilder().setName("documentKey1")
.addDocumentValues(
GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_1)));
propertyProtoMap.put(GenericDocument.PROPERTIES_FIELD,
PropertyProto.newBuilder().setName(GenericDocument.PROPERTIES_FIELD)
propertyProtoMap.put("documentKey2",
PropertyProto.newBuilder().setName("documentKey2")
.addDocumentValues(
GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_2)));
List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
package com.android.server.appsearch.external.localstorage.converter;
import static com.google.common.truth.Truth.assertThat;
@@ -50,7 +50,6 @@ public class SchemaToProtoConverterTest {
.addProperties(PropertyConfigProto.newBuilder()
.setPropertyName("subject")
.setDataType(PropertyConfigProto.DataType.Code.STRING)
.setSchemaType("")
.setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
.setIndexingConfig(
com.android.server.appsearch.proto.IndexingConfig.newBuilder()
@@ -60,7 +59,6 @@ public class SchemaToProtoConverterTest {
).addProperties(PropertyConfigProto.newBuilder()
.setPropertyName("body")
.setDataType(PropertyConfigProto.DataType.Code.STRING)
.setSchemaType("")
.setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
.setIndexingConfig(
com.android.server.appsearch.proto.IndexingConfig.newBuilder()
@@ -94,7 +92,6 @@ public class SchemaToProtoConverterTest {
.addProperties(PropertyConfigProto.newBuilder()
.setPropertyName("artist")
.setDataType(PropertyConfigProto.DataType.Code.STRING)
.setSchemaType("")
.setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
.setIndexingConfig(
com.android.server.appsearch.proto.IndexingConfig.newBuilder()
@@ -104,7 +101,6 @@ public class SchemaToProtoConverterTest {
).addProperties(PropertyConfigProto.newBuilder()
.setPropertyName("pubDate")
.setDataType(PropertyConfigProto.DataType.Code.INT64)
.setSchemaType("")
.setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
.setIndexingConfig(
com.android.server.appsearch.proto.IndexingConfig.newBuilder()

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.server.appsearch.external.localbackend.converter;
package com.android.server.appsearch.external.localstorage.converter;
import static com.google.common.truth.Truth.assertThat;
@@ -123,7 +123,7 @@ public class SnippetTest {
for (SearchResultProto.ResultProto proto : searchResultProto.getResultsList()) {
SearchResult result = SearchResultToProtoConverter.convertSearchResult(proto);
assertThat(result.getMatches()).isEqualTo(null);
assertThat(result.getMatches()).isEmpty();
}
}