Merge "Update framework from jetpack." into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1e258ecf1d
@@ -37,6 +37,8 @@ import java.util.Objects;
|
||||
* @param <ValueType> The type of result object for successful calls.
|
||||
*/
|
||||
public final class AppSearchResult<ValueType> implements Parcelable {
|
||||
private static final String TAG = "AppSearchResult";
|
||||
|
||||
/**
|
||||
* Result codes from {@link AppSearchSession} methods.
|
||||
* @hide
|
||||
@@ -246,14 +248,22 @@ public final class AppSearchResult<ValueType> implements Parcelable {
|
||||
@NonNull
|
||||
public static <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
|
||||
@NonNull Throwable t) {
|
||||
Log.d("AppSearchResult", "Converting throwable to failed result.", t);
|
||||
// Log for traceability. NOT_FOUND is logged at VERBOSE because this error can occur during
|
||||
// the regular operation of the system (b/183550974). Everything else is logged at DEBUG.
|
||||
if (t instanceof AppSearchException
|
||||
&& ((AppSearchException) t).getResultCode() == RESULT_NOT_FOUND) {
|
||||
Log.v(TAG, "Converting throwable to failed result: " + t);
|
||||
} else {
|
||||
Log.d(TAG, "Converting throwable to failed result.", t);
|
||||
}
|
||||
|
||||
if (t instanceof AppSearchException) {
|
||||
return ((AppSearchException) t).toAppSearchResult();
|
||||
}
|
||||
|
||||
String exceptionClass = t.getClass().getSimpleName();
|
||||
@AppSearchResult.ResultCode int resultCode;
|
||||
if (t instanceof IllegalStateException) {
|
||||
if (t instanceof IllegalStateException || t instanceof NullPointerException) {
|
||||
resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
|
||||
} else if (t instanceof IllegalArgumentException) {
|
||||
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
|
||||
@@ -262,6 +272,6 @@ public final class AppSearchResult<ValueType> implements Parcelable {
|
||||
} else {
|
||||
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
|
||||
}
|
||||
return AppSearchResult.newFailedResult(resultCode, t.getMessage());
|
||||
return AppSearchResult.newFailedResult(resultCode, exceptionClass + ": " + t.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public final class AppSearchSchema {
|
||||
|
||||
/** @hide */
|
||||
public AppSearchSchema(@NonNull Bundle bundle) {
|
||||
Preconditions.checkNotNull(bundle);
|
||||
Objects.requireNonNull(bundle);
|
||||
mBundle = bundle;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public final class AppSearchSchema {
|
||||
|
||||
/** Creates a new {@link AppSearchSchema.Builder}. */
|
||||
public Builder(@NonNull String schemaType) {
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Objects.requireNonNull(schemaType);
|
||||
mSchemaType = schemaType;
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ public final class AppSearchSchema {
|
||||
@NonNull
|
||||
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(propertyConfig);
|
||||
Objects.requireNonNull(propertyConfig);
|
||||
String name = propertyConfig.getName();
|
||||
if (!mPropertyNames.add(name)) {
|
||||
throw new IllegalSchemaException("Property defined more than once: " + name);
|
||||
@@ -246,7 +246,7 @@ public final class AppSearchSchema {
|
||||
@Nullable private Integer mHashCode;
|
||||
|
||||
PropertyConfig(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -712,7 +712,7 @@ public final class AppSearchSchema {
|
||||
/** Returns the logical schema-type of the contents of this document property. */
|
||||
@NonNull
|
||||
public String getSchemaType() {
|
||||
return Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
|
||||
return Objects.requireNonNull(mBundle.getString(SCHEMA_TYPE_FIELD));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -755,7 +755,7 @@ public final class AppSearchSchema {
|
||||
@NonNull
|
||||
public DocumentPropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Objects.requireNonNull(schemaType);
|
||||
mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -101,11 +102,11 @@ public class GenericDocument {
|
||||
* @hide
|
||||
*/
|
||||
public GenericDocument(@NonNull Bundle bundle) {
|
||||
Preconditions.checkNotNull(bundle);
|
||||
Objects.requireNonNull(bundle);
|
||||
mBundle = bundle;
|
||||
mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
|
||||
mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
|
||||
mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
|
||||
mProperties = Objects.requireNonNull(bundle.getParcelable(PROPERTIES_FIELD));
|
||||
mUri = Objects.requireNonNull(mBundle.getString(URI_FIELD));
|
||||
mSchemaType = Objects.requireNonNull(mBundle.getString(SCHEMA_TYPE_FIELD));
|
||||
mCreationTimestampMillis =
|
||||
mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
|
||||
}
|
||||
@@ -199,7 +200,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public Object getProperty(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
Object property = mProperties.get(key);
|
||||
if (property instanceof ArrayList) {
|
||||
return getPropertyBytesArray(key);
|
||||
@@ -218,7 +219,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public String getPropertyString(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
String[] propertyArray = getPropertyStringArray(key);
|
||||
if (propertyArray == null || propertyArray.length == 0) {
|
||||
return null;
|
||||
@@ -235,7 +236,7 @@ public class GenericDocument {
|
||||
* there is no such key or the value is of a different type.
|
||||
*/
|
||||
public long getPropertyLong(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
long[] propertyArray = getPropertyLongArray(key);
|
||||
if (propertyArray == null || propertyArray.length == 0) {
|
||||
return 0;
|
||||
@@ -252,7 +253,7 @@ public class GenericDocument {
|
||||
* if there is no such key or the value is of a different type.
|
||||
*/
|
||||
public double getPropertyDouble(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
double[] propertyArray = getPropertyDoubleArray(key);
|
||||
if (propertyArray == null || propertyArray.length == 0) {
|
||||
return 0.0;
|
||||
@@ -269,7 +270,7 @@ public class GenericDocument {
|
||||
* false} if there is no such key or the value is of a different type.
|
||||
*/
|
||||
public boolean getPropertyBoolean(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
boolean[] propertyArray = getPropertyBooleanArray(key);
|
||||
if (propertyArray == null || propertyArray.length == 0) {
|
||||
return false;
|
||||
@@ -287,7 +288,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public byte[] getPropertyBytes(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
byte[][] propertyArray = getPropertyBytesArray(key);
|
||||
if (propertyArray == null || propertyArray.length == 0) {
|
||||
return null;
|
||||
@@ -305,7 +306,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public GenericDocument getPropertyDocument(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
GenericDocument[] propertyArray = getPropertyDocumentArray(key);
|
||||
if (propertyArray == null || propertyArray.length == 0) {
|
||||
return null;
|
||||
@@ -342,7 +343,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public String[] getPropertyStringArray(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
return getAndCastPropertyArray(key, String[].class);
|
||||
}
|
||||
|
||||
@@ -355,7 +356,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public long[] getPropertyLongArray(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
return getAndCastPropertyArray(key, long[].class);
|
||||
}
|
||||
|
||||
@@ -368,7 +369,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public double[] getPropertyDoubleArray(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
return getAndCastPropertyArray(key, double[].class);
|
||||
}
|
||||
|
||||
@@ -381,7 +382,7 @@ public class GenericDocument {
|
||||
*/
|
||||
@Nullable
|
||||
public boolean[] getPropertyBooleanArray(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
return getAndCastPropertyArray(key, boolean[].class);
|
||||
}
|
||||
|
||||
@@ -396,7 +397,7 @@ public class GenericDocument {
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public byte[][] getPropertyBytesArray(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
|
||||
if (bundles == null || bundles.size() == 0) {
|
||||
return null;
|
||||
@@ -428,7 +429,7 @@ public class GenericDocument {
|
||||
@SuppressLint("ArrayReturn")
|
||||
@Nullable
|
||||
public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
|
||||
Preconditions.checkNotNull(key);
|
||||
Objects.requireNonNull(key);
|
||||
Parcelable[] bundles = getAndCastPropertyArray(key, Parcelable[].class);
|
||||
if (bundles == null || bundles.length == 0) {
|
||||
return null;
|
||||
@@ -591,9 +592,9 @@ public class GenericDocument {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Builder(@NonNull String namespace, @NonNull String uri, @NonNull String schemaType) {
|
||||
Preconditions.checkNotNull(namespace);
|
||||
Preconditions.checkNotNull(uri);
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Objects.requireNonNull(namespace);
|
||||
Objects.requireNonNull(uri);
|
||||
Objects.requireNonNull(schemaType);
|
||||
mBuilderTypeInstance = (BuilderType) this;
|
||||
mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
|
||||
mBundle.putString(GenericDocument.URI_FIELD, uri);
|
||||
@@ -682,8 +683,8 @@ public class GenericDocument {
|
||||
@NonNull
|
||||
public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(values);
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(values);
|
||||
putInPropertyBundle(key, values);
|
||||
return mBuilderTypeInstance;
|
||||
}
|
||||
@@ -694,15 +695,14 @@ public class GenericDocument {
|
||||
*
|
||||
* @param key the key associated with the {@code values}.
|
||||
* @param values the {@code boolean} values of the property.
|
||||
* @throws IllegalArgumentException if no values are provided or if values exceed maximum
|
||||
* repeated property length.
|
||||
* @throws IllegalArgumentException if values exceed maximum repeated property length.
|
||||
* @throws IllegalStateException if the builder has already been used.
|
||||
*/
|
||||
@NonNull
|
||||
public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(values);
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(values);
|
||||
putInPropertyBundle(key, values);
|
||||
return mBuilderTypeInstance;
|
||||
}
|
||||
@@ -712,15 +712,14 @@ public class GenericDocument {
|
||||
*
|
||||
* @param key the key associated with the {@code values}.
|
||||
* @param values the {@code long} values of the property.
|
||||
* @throws IllegalArgumentException if no values are provided or if values exceed maximum
|
||||
* repeated property length.
|
||||
* @throws IllegalArgumentException if values exceed maximum repeated property length.
|
||||
* @throws IllegalStateException if the builder has already been used.
|
||||
*/
|
||||
@NonNull
|
||||
public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(values);
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(values);
|
||||
putInPropertyBundle(key, values);
|
||||
return mBuilderTypeInstance;
|
||||
}
|
||||
@@ -730,15 +729,14 @@ public class GenericDocument {
|
||||
*
|
||||
* @param key the key associated with the {@code values}.
|
||||
* @param values the {@code double} values of the property.
|
||||
* @throws IllegalArgumentException if no values are provided or if values exceed maximum
|
||||
* repeated property length.
|
||||
* @throws IllegalArgumentException if values exceed maximum repeated property length.
|
||||
* @throws IllegalStateException if the builder has already been used.
|
||||
*/
|
||||
@NonNull
|
||||
public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(values);
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(values);
|
||||
putInPropertyBundle(key, values);
|
||||
return mBuilderTypeInstance;
|
||||
}
|
||||
@@ -755,8 +753,8 @@ public class GenericDocument {
|
||||
@NonNull
|
||||
public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(values);
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(values);
|
||||
putInPropertyBundle(key, values);
|
||||
return mBuilderTypeInstance;
|
||||
}
|
||||
@@ -776,8 +774,8 @@ public class GenericDocument {
|
||||
public BuilderType setPropertyDocument(
|
||||
@NonNull String key, @NonNull GenericDocument... values) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(key);
|
||||
Preconditions.checkNotNull(values);
|
||||
Objects.requireNonNull(key);
|
||||
Objects.requireNonNull(values);
|
||||
putInPropertyBundle(key, values);
|
||||
return mBuilderTypeInstance;
|
||||
}
|
||||
@@ -850,9 +848,7 @@ public class GenericDocument {
|
||||
}
|
||||
|
||||
private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
|
||||
if (length == 0) {
|
||||
throw new IllegalArgumentException("The input array is empty.");
|
||||
} else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
|
||||
if (length > MAX_REPEATED_PROPERTY_LENGTH) {
|
||||
throw new IllegalArgumentException(
|
||||
"Repeated property \""
|
||||
+ key
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -52,9 +53,9 @@ public final class 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);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
mUris = Objects.requireNonNull(uris);
|
||||
mTypePropertyPathsMap = Objects.requireNonNull(typePropertyPathsMap);
|
||||
}
|
||||
|
||||
/** Returns the namespace attached to the request. */
|
||||
@@ -114,7 +115,7 @@ public final class GetByUriRequest {
|
||||
|
||||
/** Creates a {@link GetByUriRequest.Builder} instance. */
|
||||
public Builder(@NonNull String namespace) {
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +125,7 @@ public final class GetByUriRequest {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addUris(@NonNull String... uris) {
|
||||
Preconditions.checkNotNull(uris);
|
||||
Objects.requireNonNull(uris);
|
||||
return addUris(Arrays.asList(uris));
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ public final class GetByUriRequest {
|
||||
@NonNull
|
||||
public Builder addUris(@NonNull Collection<String> uris) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(uris);
|
||||
Objects.requireNonNull(uris);
|
||||
mUris.addAll(uris);
|
||||
return this;
|
||||
}
|
||||
@@ -161,11 +162,11 @@ public final class GetByUriRequest {
|
||||
public Builder addProjection(
|
||||
@NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Preconditions.checkNotNull(propertyPaths);
|
||||
Objects.requireNonNull(schemaType);
|
||||
Objects.requireNonNull(propertyPaths);
|
||||
List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
|
||||
for (String propertyPath : propertyPaths) {
|
||||
Preconditions.checkNotNull(propertyPath);
|
||||
Objects.requireNonNull(propertyPath);
|
||||
propertyPathsList.add(propertyPath);
|
||||
}
|
||||
mProjectionTypePropertyPaths.put(schemaType, propertyPathsList);
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.util.ArraySet;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/** The response class of {@link AppSearchSession#getSchema} */
|
||||
@@ -34,7 +35,7 @@ public class GetSchemaResponse {
|
||||
private final Bundle mBundle;
|
||||
|
||||
GetSchemaResponse(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.app.appsearch.util.BundleUtil;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import java.util.Objects;
|
||||
|
||||
/** This class represents a uniquely identifiable package. */
|
||||
public class PackageIdentifier {
|
||||
@@ -43,7 +43,7 @@ public class PackageIdentifier {
|
||||
|
||||
/** @hide */
|
||||
public PackageIdentifier(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -54,12 +54,12 @@ public class PackageIdentifier {
|
||||
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
|
||||
return Objects.requireNonNull(mBundle.getString(PACKAGE_NAME_FIELD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public byte[] getSha256Certificate() {
|
||||
return Preconditions.checkNotNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
|
||||
return Objects.requireNonNull(mBundle.getByteArray(SHA256_CERTIFICATE_FIELD));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Encapsulates a request to index documents into an {@link AppSearchSession} database.
|
||||
@@ -61,7 +62,7 @@ public final class PutDocumentsRequest {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
|
||||
Preconditions.checkNotNull(documents);
|
||||
Objects.requireNonNull(documents);
|
||||
return addGenericDocuments(Arrays.asList(documents));
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ public final class PutDocumentsRequest {
|
||||
public Builder addGenericDocuments(
|
||||
@NonNull Collection<? extends GenericDocument> documents) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(documents);
|
||||
Objects.requireNonNull(documents);
|
||||
mDocuments.addAll(documents);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.internal.util.Preconditions;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -65,7 +66,7 @@ public final class RemoveByUriRequest {
|
||||
|
||||
/** Creates a {@link RemoveByUriRequest.Builder} instance. */
|
||||
public Builder(@NonNull String namespace) {
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +76,7 @@ public final class RemoveByUriRequest {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addUris(@NonNull String... uris) {
|
||||
Preconditions.checkNotNull(uris);
|
||||
Objects.requireNonNull(uris);
|
||||
return addUris(Arrays.asList(uris));
|
||||
}
|
||||
|
||||
@@ -87,7 +88,7 @@ public final class RemoveByUriRequest {
|
||||
@NonNull
|
||||
public Builder addUris(@NonNull Collection<String> uris) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(uris);
|
||||
Objects.requireNonNull(uris);
|
||||
mUris.addAll(uris);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A request to report usage of a document owned by another app from a system UI surface.
|
||||
*
|
||||
@@ -42,10 +44,10 @@ public final class ReportSystemUsageRequest {
|
||||
@NonNull String namespace,
|
||||
@NonNull String uri,
|
||||
long usageTimeMillis) {
|
||||
mPackageName = Preconditions.checkNotNull(packageName);
|
||||
mDatabase = Preconditions.checkNotNull(database);
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mUri = Preconditions.checkNotNull(uri);
|
||||
mPackageName = Objects.requireNonNull(packageName);
|
||||
mDatabase = Objects.requireNonNull(database);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
mUri = Objects.requireNonNull(uri);
|
||||
mUsageTimeMillis = usageTimeMillis;
|
||||
}
|
||||
|
||||
@@ -95,9 +97,9 @@ public final class ReportSystemUsageRequest {
|
||||
/** Creates a {@link ReportSystemUsageRequest.Builder} instance. */
|
||||
public Builder(
|
||||
@NonNull String packageName, @NonNull String database, @NonNull String namespace) {
|
||||
mPackageName = Preconditions.checkNotNull(packageName);
|
||||
mDatabase = Preconditions.checkNotNull(database);
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mPackageName = Objects.requireNonNull(packageName);
|
||||
mDatabase = Objects.requireNonNull(database);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +112,7 @@ public final class ReportSystemUsageRequest {
|
||||
@NonNull
|
||||
public ReportSystemUsageRequest.Builder setUri(@NonNull String uri) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(uri);
|
||||
Objects.requireNonNull(uri);
|
||||
mUri = uri;
|
||||
return this;
|
||||
}
|
||||
@@ -142,7 +144,7 @@ public final class ReportSystemUsageRequest {
|
||||
@NonNull
|
||||
public ReportSystemUsageRequest build() {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
|
||||
Objects.requireNonNull(mUri, "ReportUsageRequest is missing a URI");
|
||||
if (mUsageTimeMillis == null) {
|
||||
mUsageTimeMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A request to report usage of a document.
|
||||
*
|
||||
@@ -33,8 +35,8 @@ public final class ReportUsageRequest {
|
||||
private final long mUsageTimeMillis;
|
||||
|
||||
ReportUsageRequest(@NonNull String namespace, @NonNull String uri, long usageTimeMillis) {
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mUri = Preconditions.checkNotNull(uri);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
mUri = Objects.requireNonNull(uri);
|
||||
mUsageTimeMillis = usageTimeMillis;
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ public final class ReportUsageRequest {
|
||||
|
||||
/** Creates a {@link ReportUsageRequest.Builder} instance. */
|
||||
public Builder(@NonNull String namespace) {
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +84,7 @@ public final class ReportUsageRequest {
|
||||
@NonNull
|
||||
public ReportUsageRequest.Builder setUri(@NonNull String uri) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(uri);
|
||||
Objects.requireNonNull(uri);
|
||||
mUri = uri;
|
||||
return this;
|
||||
}
|
||||
@@ -114,7 +116,7 @@ public final class ReportUsageRequest {
|
||||
@NonNull
|
||||
public ReportUsageRequest build() {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(mUri, "ReportUsageRequest is missing a URI");
|
||||
Objects.requireNonNull(mUri, "ReportUsageRequest is missing a URI");
|
||||
if (mUsageTimeMillis == null) {
|
||||
mUsageTimeMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class SearchResult {
|
||||
|
||||
/** @hide */
|
||||
public SearchResult(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -77,8 +77,7 @@ public final class SearchResult {
|
||||
public GenericDocument getGenericDocument() {
|
||||
if (mDocument == null) {
|
||||
mDocument =
|
||||
new GenericDocument(
|
||||
Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
|
||||
new GenericDocument(Objects.requireNonNull(mBundle.getBundle(DOCUMENT_FIELD)));
|
||||
}
|
||||
return mDocument;
|
||||
}
|
||||
@@ -95,7 +94,7 @@ public final class SearchResult {
|
||||
public List<MatchInfo> getMatches() {
|
||||
if (mMatches == null) {
|
||||
List<Bundle> matchBundles =
|
||||
Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
|
||||
Objects.requireNonNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
|
||||
mMatches = new ArrayList<>(matchBundles.size());
|
||||
for (int i = 0; i < matchBundles.size(); i++) {
|
||||
MatchInfo matchInfo = new MatchInfo(matchBundles.get(i), getGenericDocument());
|
||||
@@ -112,7 +111,7 @@ public final class SearchResult {
|
||||
*/
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
|
||||
return Objects.requireNonNull(mBundle.getString(PACKAGE_NAME_FIELD));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +121,7 @@ public final class SearchResult {
|
||||
*/
|
||||
@NonNull
|
||||
public String getDatabaseName() {
|
||||
return Preconditions.checkNotNull(mBundle.getString(DATABASE_NAME_FIELD));
|
||||
return Objects.requireNonNull(mBundle.getString(DATABASE_NAME_FIELD));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,8 +168,8 @@ public final class SearchResult {
|
||||
* @param databaseName the database name the matched document belongs to.
|
||||
*/
|
||||
public Builder(@NonNull String packageName, @NonNull String databaseName) {
|
||||
mBundle.putString(PACKAGE_NAME_FIELD, Preconditions.checkNotNull(packageName));
|
||||
mBundle.putString(DATABASE_NAME_FIELD, Preconditions.checkNotNull(databaseName));
|
||||
mBundle.putString(PACKAGE_NAME_FIELD, Objects.requireNonNull(packageName));
|
||||
mBundle.putString(DATABASE_NAME_FIELD, Objects.requireNonNull(databaseName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,9 +311,9 @@ public final class SearchResult {
|
||||
@Nullable private MatchRange mWindowRange;
|
||||
|
||||
MatchInfo(@NonNull Bundle bundle, @Nullable GenericDocument document) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
mDocument = document;
|
||||
mPropertyPath = Preconditions.checkNotNull(bundle.getString(PROPERTY_PATH_FIELD));
|
||||
mPropertyPath = Objects.requireNonNull(bundle.getString(PROPERTY_PATH_FIELD));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,7 +448,7 @@ public final class SearchResult {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mBundle.putString(
|
||||
SearchResult.MatchInfo.PROPERTY_PATH_FIELD,
|
||||
Preconditions.checkNotNull(propertyPath));
|
||||
Objects.requireNonNull(propertyPath));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -461,7 +460,7 @@ public final class SearchResult {
|
||||
@NonNull
|
||||
public Builder setExactMatchRange(@NonNull MatchRange matchRange) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(matchRange);
|
||||
Objects.requireNonNull(matchRange);
|
||||
mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, matchRange.getStart());
|
||||
mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, matchRange.getEnd());
|
||||
return this;
|
||||
@@ -475,7 +474,7 @@ public final class SearchResult {
|
||||
@NonNull
|
||||
public Builder setSnippetRange(@NonNull MatchRange matchRange) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(matchRange);
|
||||
Objects.requireNonNull(matchRange);
|
||||
mBundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, matchRange.getStart());
|
||||
mBundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, matchRange.getEnd());
|
||||
return this;
|
||||
|
||||
@@ -20,11 +20,10 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class represents a page of {@link SearchResult}s
|
||||
@@ -41,7 +40,7 @@ public class SearchResultPage {
|
||||
@NonNull private final Bundle mBundle;
|
||||
|
||||
public SearchResultPage(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
mNextPageToken = mBundle.getLong(NEXT_PAGE_TOKEN_FIELD);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -176,7 +177,7 @@ public final class SearchSpec {
|
||||
|
||||
/** @hide */
|
||||
public SearchSpec(@NonNull Bundle bundle) {
|
||||
Preconditions.checkNotNull(bundle);
|
||||
Objects.requireNonNull(bundle);
|
||||
mBundle = bundle;
|
||||
}
|
||||
|
||||
@@ -342,7 +343,7 @@ public final class SearchSpec {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addFilterSchemas(@NonNull String... schemas) {
|
||||
Preconditions.checkNotNull(schemas);
|
||||
Objects.requireNonNull(schemas);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
return addFilterSchemas(Arrays.asList(schemas));
|
||||
}
|
||||
@@ -355,7 +356,7 @@ public final class SearchSpec {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
|
||||
Preconditions.checkNotNull(schemas);
|
||||
Objects.requireNonNull(schemas);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mSchemas.addAll(schemas);
|
||||
return this;
|
||||
@@ -369,7 +370,7 @@ public final class SearchSpec {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addFilterNamespaces(@NonNull String... namespaces) {
|
||||
Preconditions.checkNotNull(namespaces);
|
||||
Objects.requireNonNull(namespaces);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
return addFilterNamespaces(Arrays.asList(namespaces));
|
||||
}
|
||||
@@ -382,7 +383,7 @@ public final class SearchSpec {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
|
||||
Preconditions.checkNotNull(namespaces);
|
||||
Objects.requireNonNull(namespaces);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mNamespaces.addAll(namespaces);
|
||||
return this;
|
||||
@@ -398,7 +399,7 @@ public final class SearchSpec {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addFilterPackageNames(@NonNull String... packageNames) {
|
||||
Preconditions.checkNotNull(packageNames);
|
||||
Objects.requireNonNull(packageNames);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
return addFilterPackageNames(Arrays.asList(packageNames));
|
||||
}
|
||||
@@ -413,7 +414,7 @@ public final class SearchSpec {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addFilterPackageNames(@NonNull Collection<String> packageNames) {
|
||||
Preconditions.checkNotNull(packageNames);
|
||||
Objects.requireNonNull(packageNames);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mPackageNames.addAll(packageNames);
|
||||
return this;
|
||||
@@ -586,11 +587,11 @@ public final class SearchSpec {
|
||||
public SearchSpec.Builder addProjection(
|
||||
@NonNull String schema, @NonNull Collection<String> propertyPaths) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(schema);
|
||||
Preconditions.checkNotNull(propertyPaths);
|
||||
Objects.requireNonNull(schema);
|
||||
Objects.requireNonNull(propertyPaths);
|
||||
ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
|
||||
for (String propertyPath : propertyPaths) {
|
||||
Preconditions.checkNotNull(propertyPath);
|
||||
Objects.requireNonNull(propertyPath);
|
||||
propertyPathsArrayList.add(propertyPath);
|
||||
}
|
||||
mProjectionTypePropertyMasks.putStringArrayList(schema, propertyPathsArrayList);
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -94,10 +95,10 @@ public final class SetSchemaRequest {
|
||||
@NonNull Map<String, Migrator> migrators,
|
||||
boolean forceOverride,
|
||||
int version) {
|
||||
mSchemas = Preconditions.checkNotNull(schemas);
|
||||
mSchemasNotDisplayedBySystem = Preconditions.checkNotNull(schemasNotDisplayedBySystem);
|
||||
mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
|
||||
mMigrators = Preconditions.checkNotNull(migrators);
|
||||
mSchemas = Objects.requireNonNull(schemas);
|
||||
mSchemasNotDisplayedBySystem = Objects.requireNonNull(schemasNotDisplayedBySystem);
|
||||
mSchemasVisibleToPackages = Objects.requireNonNull(schemasVisibleToPackages);
|
||||
mMigrators = Objects.requireNonNull(migrators);
|
||||
mForceOverride = forceOverride;
|
||||
mVersion = version;
|
||||
}
|
||||
@@ -192,7 +193,7 @@ public final class SetSchemaRequest {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
|
||||
Preconditions.checkNotNull(schemas);
|
||||
Objects.requireNonNull(schemas);
|
||||
return addSchemas(Arrays.asList(schemas));
|
||||
}
|
||||
|
||||
@@ -206,7 +207,7 @@ public final class SetSchemaRequest {
|
||||
@NonNull
|
||||
public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(schemas);
|
||||
Objects.requireNonNull(schemas);
|
||||
mSchemas.addAll(schemas);
|
||||
return this;
|
||||
}
|
||||
@@ -231,7 +232,7 @@ public final class SetSchemaRequest {
|
||||
@NonNull
|
||||
public Builder setSchemaTypeDisplayedBySystem(
|
||||
@NonNull String schemaType, boolean displayed) {
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Objects.requireNonNull(schemaType);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
|
||||
if (displayed) {
|
||||
@@ -270,8 +271,8 @@ public final class SetSchemaRequest {
|
||||
@NonNull String schemaType,
|
||||
boolean visible,
|
||||
@NonNull PackageIdentifier packageIdentifier) {
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Preconditions.checkNotNull(packageIdentifier);
|
||||
Objects.requireNonNull(schemaType);
|
||||
Objects.requireNonNull(packageIdentifier);
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
|
||||
Set<PackageIdentifier> packageIdentifiers = mSchemasVisibleToPackages.get(schemaType);
|
||||
@@ -321,8 +322,8 @@ public final class SetSchemaRequest {
|
||||
@NonNull
|
||||
@SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
|
||||
public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Preconditions.checkNotNull(migrator);
|
||||
Objects.requireNonNull(schemaType);
|
||||
Objects.requireNonNull(migrator);
|
||||
mMigrators.put(schemaType, migrator);
|
||||
return this;
|
||||
}
|
||||
@@ -350,7 +351,7 @@ public final class SetSchemaRequest {
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
|
||||
Preconditions.checkNotNull(migrators);
|
||||
Objects.requireNonNull(migrators);
|
||||
mMigrators.putAll(migrators);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/** The response class of {@link AppSearchSession#setSchema} */
|
||||
@@ -61,8 +62,8 @@ public class SetSchemaResponse {
|
||||
@Nullable private Set<String> mIncompatibleTypes;
|
||||
|
||||
SetSchemaResponse(@NonNull Bundle bundle, @NonNull List<MigrationFailure> migrationFailures) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mMigrationFailures = Preconditions.checkNotNull(migrationFailures);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
mMigrationFailures = Objects.requireNonNull(migrationFailures);
|
||||
}
|
||||
|
||||
SetSchemaResponse(@NonNull Bundle bundle) {
|
||||
@@ -103,7 +104,7 @@ public class SetSchemaResponse {
|
||||
if (mDeletedTypes == null) {
|
||||
mDeletedTypes =
|
||||
new ArraySet<>(
|
||||
Preconditions.checkNotNull(
|
||||
Objects.requireNonNull(
|
||||
mBundle.getStringArrayList(DELETED_TYPES_FIELD)));
|
||||
}
|
||||
return Collections.unmodifiableSet(mDeletedTypes);
|
||||
@@ -118,7 +119,7 @@ public class SetSchemaResponse {
|
||||
if (mMigratedTypes == null) {
|
||||
mMigratedTypes =
|
||||
new ArraySet<>(
|
||||
Preconditions.checkNotNull(
|
||||
Objects.requireNonNull(
|
||||
mBundle.getStringArrayList(MIGRATED_TYPES_FIELD)));
|
||||
}
|
||||
return Collections.unmodifiableSet(mMigratedTypes);
|
||||
@@ -139,7 +140,7 @@ public class SetSchemaResponse {
|
||||
if (mIncompatibleTypes == null) {
|
||||
mIncompatibleTypes =
|
||||
new ArraySet<>(
|
||||
Preconditions.checkNotNull(
|
||||
Objects.requireNonNull(
|
||||
mBundle.getStringArrayList(INCOMPATIBLE_TYPES_FIELD)));
|
||||
}
|
||||
return Collections.unmodifiableSet(mIncompatibleTypes);
|
||||
@@ -173,7 +174,7 @@ public class SetSchemaResponse {
|
||||
public Builder addMigrationFailures(
|
||||
@NonNull Collection<MigrationFailure> migrationFailures) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mMigrationFailures.addAll(Preconditions.checkNotNull(migrationFailures));
|
||||
mMigrationFailures.addAll(Objects.requireNonNull(migrationFailures));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -181,7 +182,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mMigrationFailures.add(Preconditions.checkNotNull(migrationFailure));
|
||||
mMigrationFailures.add(Objects.requireNonNull(migrationFailure));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -189,7 +190,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addDeletedTypes(@NonNull Collection<String> deletedTypes) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mDeletedTypes.addAll(Preconditions.checkNotNull(deletedTypes));
|
||||
mDeletedTypes.addAll(Objects.requireNonNull(deletedTypes));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -197,7 +198,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addDeletedType(@NonNull String deletedType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mDeletedTypes.add(Preconditions.checkNotNull(deletedType));
|
||||
mDeletedTypes.add(Objects.requireNonNull(deletedType));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -205,7 +206,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addIncompatibleTypes(@NonNull Collection<String> incompatibleTypes) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mIncompatibleTypes.addAll(Preconditions.checkNotNull(incompatibleTypes));
|
||||
mIncompatibleTypes.addAll(Objects.requireNonNull(incompatibleTypes));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -213,7 +214,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addIncompatibleType(@NonNull String incompatibleType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mIncompatibleTypes.add(Preconditions.checkNotNull(incompatibleType));
|
||||
mIncompatibleTypes.add(Objects.requireNonNull(incompatibleType));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addMigratedTypes(@NonNull Collection<String> migratedTypes) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mMigratedTypes.addAll(Preconditions.checkNotNull(migratedTypes));
|
||||
mMigratedTypes.addAll(Objects.requireNonNull(migratedTypes));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -229,7 +230,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder addMigratedType(@NonNull String migratedType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mMigratedTypes.add(Preconditions.checkNotNull(migratedType));
|
||||
mMigratedTypes.add(Objects.requireNonNull(migratedType));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -318,7 +319,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder setSchemaType(@NonNull String schemaType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mSchemaType = Preconditions.checkNotNull(schemaType);
|
||||
mSchemaType = Objects.requireNonNull(schemaType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -326,7 +327,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder setNamespace(@NonNull String namespace) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mNamespace = Preconditions.checkNotNull(namespace);
|
||||
mNamespace = Objects.requireNonNull(namespace);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -334,7 +335,7 @@ public class SetSchemaResponse {
|
||||
@NonNull
|
||||
public Builder setUri(@NonNull String uri) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mUri = Preconditions.checkNotNull(uri);
|
||||
mUri = Objects.requireNonNull(uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -343,7 +344,7 @@ public class SetSchemaResponse {
|
||||
public Builder setAppSearchResult(@NonNull AppSearchResult<Void> appSearchResult) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkState(!appSearchResult.isSuccess(), "Input a success result");
|
||||
mFailureResult = Preconditions.checkNotNull(appSearchResult);
|
||||
mFailureResult = Objects.requireNonNull(appSearchResult);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import android.os.Bundle;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/** The response class of {@code AppSearchSession#getStorageInfo}. */
|
||||
public class StorageInfo {
|
||||
|
||||
@@ -31,7 +33,7 @@ public class StorageInfo {
|
||||
private final Bundle mBundle;
|
||||
|
||||
StorageInfo(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mBundle = Objects.requireNonNull(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,11 @@ import java.util.Set;
|
||||
public final class SchemaMigrationUtil {
|
||||
private SchemaMigrationUtil() {}
|
||||
|
||||
/** Returns all active {@link Migrator}s that need to be triggered in this migration. */
|
||||
/**
|
||||
* Returns all active {@link Migrator}s that need to be triggered in this migration.
|
||||
*
|
||||
* <p>{@link Migrator#shouldMigrate} returns {@code true} will make the {@link Migrator} active.
|
||||
*/
|
||||
@NonNull
|
||||
public static Map<String, Migrator> getActiveMigrators(
|
||||
@NonNull Set<AppSearchSchema> existingSchemas,
|
||||
|
||||
@@ -64,6 +64,8 @@ import com.android.server.appsearch.external.localstorage.stats.CallStats;
|
||||
import com.android.server.appsearch.stats.LoggerInstanceManager;
|
||||
import com.android.server.appsearch.stats.PlatformLogger;
|
||||
|
||||
import com.google.android.icing.proto.PersistType;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
@@ -364,6 +366,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
++operationFailureCount;
|
||||
}
|
||||
}
|
||||
// Now that the batch has been written. Persist the newly written data.
|
||||
impl.persistToDisk(PersistType.Code.LITE);
|
||||
invokeCallbackOnResult(callback, resultBuilder.build());
|
||||
} catch (Throwable t) {
|
||||
invokeCallbackOnError(callback, t);
|
||||
@@ -631,7 +635,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl.persistToDisk();
|
||||
impl.persistToDisk(PersistType.Code.FULL);
|
||||
invokeCallbackOnResult(callback,
|
||||
AppSearchResult.newSuccessfulResult(migrationFailureBundles));
|
||||
} catch (Throwable t) {
|
||||
@@ -708,6 +712,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
resultBuilder.setResult(uri, throwableToFailedResult(t));
|
||||
}
|
||||
}
|
||||
// Now that the batch has been written. Persist the newly written data.
|
||||
impl.persistToDisk(PersistType.Code.LITE);
|
||||
invokeCallbackOnResult(callback, resultBuilder.build());
|
||||
} catch (Throwable t) {
|
||||
invokeCallbackOnError(callback, t);
|
||||
@@ -741,6 +747,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
databaseName,
|
||||
queryExpression,
|
||||
new SearchSpec(searchSpecBundle));
|
||||
// Now that the batch has been written. Persist the newly written data.
|
||||
impl.persistToDisk(PersistType.Code.LITE);
|
||||
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
|
||||
} catch (Throwable t) {
|
||||
invokeCallbackOnError(callback, t);
|
||||
@@ -785,7 +793,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
verifyUserUnlocked(callingUserId);
|
||||
AppSearchImpl impl =
|
||||
mImplInstanceManager.getAppSearchImpl(callingUserId);
|
||||
impl.persistToDisk();
|
||||
impl.persistToDisk(PersistType.Code.FULL);
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "Unable to persist the data to disk", t);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -153,7 +154,7 @@ public class VisibilityStore {
|
||||
* AppSearchImpl.
|
||||
*/
|
||||
static final String VISIBILITY_STORE_PREFIX =
|
||||
AppSearchImpl.createPrefix(PACKAGE_NAME, DATABASE_NAME);
|
||||
PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
|
||||
|
||||
/** Namespace of documents that contain visibility settings */
|
||||
private static final String NAMESPACE = "";
|
||||
|
||||
@@ -16,10 +16,18 @@
|
||||
|
||||
package com.android.server.appsearch.external.localstorage;
|
||||
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPackagePrefix;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getDatabaseName;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPackageName;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.getPrefix;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefix;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefixesFromDocument;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.WorkerThread;
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
import android.app.appsearch.AppSearchSchema;
|
||||
import android.app.appsearch.GenericDocument;
|
||||
import android.app.appsearch.GetByUriRequest;
|
||||
@@ -39,7 +47,6 @@ import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.ResultCodeToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
|
||||
@@ -66,7 +73,6 @@ import com.google.android.icing.proto.OptimizeResultProto;
|
||||
import com.google.android.icing.proto.PersistToDiskResultProto;
|
||||
import com.google.android.icing.proto.PersistType;
|
||||
import com.google.android.icing.proto.PropertyConfigProto;
|
||||
import com.google.android.icing.proto.PropertyProto;
|
||||
import com.google.android.icing.proto.PutResultProto;
|
||||
import com.google.android.icing.proto.ReportUsageResultProto;
|
||||
import com.google.android.icing.proto.ResetResultProto;
|
||||
@@ -89,6 +95,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@@ -132,10 +139,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
public final class AppSearchImpl implements Closeable {
|
||||
private static final String TAG = "AppSearchImpl";
|
||||
|
||||
@VisibleForTesting static final char DATABASE_DELIMITER = '/';
|
||||
|
||||
@VisibleForTesting static final char PACKAGE_DELIMITER = '$';
|
||||
|
||||
@VisibleForTesting static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
|
||||
@VisibleForTesting static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
|
||||
@VisibleForTesting static final int CHECK_OPTIMIZE_INTERVAL = 100;
|
||||
@@ -148,11 +151,12 @@ public final class AppSearchImpl implements Closeable {
|
||||
@GuardedBy("mReadWriteLock")
|
||||
private final VisibilityStore mVisibilityStoreLocked;
|
||||
|
||||
// This map contains schemaTypes for all package-database prefixes. All values in the map are
|
||||
// prefixed with the package-database prefix.
|
||||
// TODO(b/172360376): Check if this can be replaced with an ArrayMap
|
||||
// This map contains schema types and SchemaTypeConfigProtos for all package-database
|
||||
// prefixes. It maps each package-database prefix to an inner-map. The inner-map maps each
|
||||
// prefixed schema type to its respective SchemaTypeConfigProto.
|
||||
@GuardedBy("mReadWriteLock")
|
||||
private final Map<String, Set<String>> mSchemaMapLocked = new HashMap<>();
|
||||
private final Map<String, Map<String, SchemaTypeConfigProto>> mSchemaMapLocked =
|
||||
new ArrayMap<>();
|
||||
|
||||
// This map contains namespaces for all package-database prefixes. All values in the map are
|
||||
// prefixed with the package-database prefix.
|
||||
@@ -182,9 +186,9 @@ public final class AppSearchImpl implements Closeable {
|
||||
int userId,
|
||||
@NonNull String globalQuerierPackage)
|
||||
throws AppSearchException {
|
||||
Preconditions.checkNotNull(icingDir);
|
||||
Preconditions.checkNotNull(context);
|
||||
Preconditions.checkNotNull(globalQuerierPackage);
|
||||
Objects.requireNonNull(icingDir);
|
||||
Objects.requireNonNull(context);
|
||||
Objects.requireNonNull(globalQuerierPackage);
|
||||
AppSearchImpl appSearchImpl =
|
||||
new AppSearchImpl(icingDir, context, userId, globalQuerierPackage);
|
||||
appSearchImpl.initializeVisibilityStore();
|
||||
@@ -229,7 +233,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
// Populate schema map
|
||||
for (SchemaTypeConfigProto schema : schemaProto.getTypesList()) {
|
||||
String prefixedSchemaType = schema.getSchemaType();
|
||||
addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), prefixedSchemaType);
|
||||
addToMap(mSchemaMapLocked, getPrefix(prefixedSchemaType), schema);
|
||||
}
|
||||
|
||||
// Populate namespace map
|
||||
@@ -278,7 +282,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
return;
|
||||
}
|
||||
|
||||
persistToDisk();
|
||||
persistToDisk(PersistType.Code.FULL);
|
||||
mIcingSearchEngineLocked.close();
|
||||
mClosedLocked = true;
|
||||
} catch (AppSearchException e) {
|
||||
@@ -364,7 +368,14 @@ public final class AppSearchImpl implements Closeable {
|
||||
}
|
||||
|
||||
// Update derived data structures.
|
||||
mSchemaMapLocked.put(prefix, rewrittenSchemaResults.mRewrittenPrefixedTypes);
|
||||
for (SchemaTypeConfigProto schemaTypeConfigProto :
|
||||
rewrittenSchemaResults.mRewrittenPrefixedTypes.values()) {
|
||||
addToMap(mSchemaMapLocked, prefix, schemaTypeConfigProto);
|
||||
}
|
||||
|
||||
for (String schemaType : rewrittenSchemaResults.mDeletedPrefixedTypes) {
|
||||
removeFromMap(mSchemaMapLocked, prefix, schemaType);
|
||||
}
|
||||
|
||||
Set<String> prefixedSchemasNotPlatformSurfaceable =
|
||||
new ArraySet<>(schemasNotPlatformSurfaceable.size());
|
||||
@@ -586,7 +597,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
mReadWriteLock.readLock().lock();
|
||||
try {
|
||||
throwIfClosedLocked();
|
||||
|
||||
String prefix = createPrefix(packageName, databaseName);
|
||||
List<TypePropertyMask> nonPrefixedPropertyMasks =
|
||||
TypePropertyPathToProtoConverter.toTypePropertyMaskList(typePropertyPaths);
|
||||
List<TypePropertyMask> prefixedPropertyMasks =
|
||||
@@ -597,7 +608,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
String prefixedType =
|
||||
nonPrefixedType.equals(GetByUriRequest.PROJECTION_SCHEMA_TYPE_WILDCARD)
|
||||
? nonPrefixedType
|
||||
: createPrefix(packageName, databaseName) + nonPrefixedType;
|
||||
: prefix + nonPrefixedType;
|
||||
prefixedPropertyMasks.add(
|
||||
typePropertyMask.toBuilder().setSchemaType(prefixedType).build());
|
||||
}
|
||||
@@ -607,15 +618,17 @@ public final class AppSearchImpl implements Closeable {
|
||||
.build();
|
||||
|
||||
GetResultProto getResultProto =
|
||||
mIcingSearchEngineLocked.get(
|
||||
createPrefix(packageName, databaseName) + namespace,
|
||||
uri,
|
||||
getResultSpec);
|
||||
mIcingSearchEngineLocked.get(prefix + namespace, uri, getResultSpec);
|
||||
checkSuccess(getResultProto.getStatus());
|
||||
|
||||
// The schema type map cannot be null at this point. It could only be null if no
|
||||
// schema had ever been set for that prefix. Given we have retrieved a document from
|
||||
// the index, we know a schema had to have been set.
|
||||
Map<String, SchemaTypeConfigProto> schemaTypeMap = mSchemaMapLocked.get(prefix);
|
||||
DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
|
||||
removePrefixesFromDocument(documentBuilder);
|
||||
return GenericDocumentToProtoConverter.toGenericDocument(documentBuilder.build());
|
||||
return GenericDocumentToProtoConverter.toGenericDocument(
|
||||
documentBuilder.build(), prefix, schemaTypeMap);
|
||||
} finally {
|
||||
mReadWriteLock.readLock().unlock();
|
||||
}
|
||||
@@ -726,7 +739,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
}
|
||||
} else {
|
||||
// Client didn't specify certain schemas to search over, check all schemas
|
||||
Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
|
||||
Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix).keySet();
|
||||
if (prefixedSchemas != null) {
|
||||
for (String prefixedSchema : prefixedSchemas) {
|
||||
if (packageName.equals(callerPackageName)
|
||||
@@ -816,7 +829,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
searchSpecBuilder.build(), scoringSpec, resultSpecBuilder.build());
|
||||
checkSuccess(searchResultProto.getStatus());
|
||||
|
||||
return rewriteSearchResultProto(searchResultProto);
|
||||
return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -838,7 +851,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
SearchResultProto searchResultProto =
|
||||
mIcingSearchEngineLocked.getNextPage(nextPageToken);
|
||||
checkSuccess(searchResultProto.getStatus());
|
||||
return rewriteSearchResultProto(searchResultProto);
|
||||
return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
|
||||
} finally {
|
||||
mReadWriteLock.readLock().unlock();
|
||||
}
|
||||
@@ -1104,22 +1117,31 @@ public final class AppSearchImpl implements Closeable {
|
||||
/**
|
||||
* Persists all update/delete requests to the disk.
|
||||
*
|
||||
* <p>If the app crashes after a call to PersistToDisk(), Icing would be able to fully recover
|
||||
* all data written up to this point without a costly recovery process.
|
||||
* <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#FULL}, Icing
|
||||
* would be able to fully recover all data written up to this point without a costly recovery
|
||||
* process.
|
||||
*
|
||||
* <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
|
||||
* process in next initialization. After that, Icing would still be able to recover all written
|
||||
* data.
|
||||
* <p>If the app crashes after a call to PersistToDisk with {@link PersistType.Code#LITE}, Icing
|
||||
* would trigger a costly recovery process in next initialization. After that, Icing would still
|
||||
* be able to recover all written data - excepting Usage data. Usage data is only guaranteed to
|
||||
* be safe after a call to PersistToDisk with {@link PersistType.Code#FULL}
|
||||
*
|
||||
* <p>If the app crashes after an update/delete request has been made, but before any call to
|
||||
* PersistToDisk, then all data in Icing will be lost.
|
||||
*
|
||||
* @param persistType the amount of data to persist. {@link PersistType.Code#LITE} will only
|
||||
* persist the minimal amount of data to ensure all data can be recovered. {@link
|
||||
* PersistType.Code#FULL} will persist all data necessary to prevent data loss without
|
||||
* needing data recovery.
|
||||
* @throws AppSearchException on any error that AppSearch persist data to disk.
|
||||
*/
|
||||
public void persistToDisk() throws AppSearchException {
|
||||
public void persistToDisk(@NonNull PersistType.Code persistType) throws AppSearchException {
|
||||
mReadWriteLock.writeLock().lock();
|
||||
try {
|
||||
throwIfClosedLocked();
|
||||
|
||||
PersistToDiskResultProto persistToDiskResultProto =
|
||||
mIcingSearchEngineLocked.persistToDisk(PersistType.Code.FULL);
|
||||
mIcingSearchEngineLocked.persistToDisk(persistType);
|
||||
checkSuccess(persistToDiskResultProto.getStatus());
|
||||
} finally {
|
||||
mReadWriteLock.writeLock().unlock();
|
||||
@@ -1189,8 +1211,8 @@ public final class AppSearchImpl implements Closeable {
|
||||
// Any prefixed types that used to exist in the schema, but are deleted in the new one.
|
||||
final Set<String> mDeletedPrefixedTypes = new ArraySet<>();
|
||||
|
||||
// Prefixed types that were part of the new schema.
|
||||
final Set<String> mRewrittenPrefixedTypes = new ArraySet<>();
|
||||
// Map of prefixed schema types to SchemaTypeConfigProtos that were part of the new schema.
|
||||
final Map<String, SchemaTypeConfigProto> mRewrittenPrefixedTypes = new ArrayMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1238,7 +1260,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
|
||||
// newTypesToProto is modified below, so we need a copy first
|
||||
RewrittenSchemaResults rewrittenSchemaResults = new RewrittenSchemaResults();
|
||||
rewrittenSchemaResults.mRewrittenPrefixedTypes.addAll(newTypesToProto.keySet());
|
||||
rewrittenSchemaResults.mRewrittenPrefixedTypes.putAll(newTypesToProto);
|
||||
|
||||
// Combine the existing schema (which may have types from other prefixes) with this
|
||||
// prefix's new schema. Modifies the existingSchemaBuilder.
|
||||
@@ -1263,99 +1285,6 @@ public final class AppSearchImpl implements Closeable {
|
||||
return rewrittenSchemaResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends {@code prefix} to all types and namespaces mentioned anywhere in {@code
|
||||
* documentBuilder}.
|
||||
*
|
||||
* @param documentBuilder The document to mutate
|
||||
* @param prefix The prefix to add
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static void addPrefixToDocument(
|
||||
@NonNull DocumentProto.Builder documentBuilder, @NonNull String prefix) {
|
||||
// Rewrite the type name to include/remove the prefix.
|
||||
String newSchema = prefix + documentBuilder.getSchema();
|
||||
documentBuilder.setSchema(newSchema);
|
||||
|
||||
// Rewrite the namespace to include/remove the prefix.
|
||||
documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
|
||||
|
||||
// Recurse into derived documents
|
||||
for (int propertyIdx = 0;
|
||||
propertyIdx < documentBuilder.getPropertiesCount();
|
||||
propertyIdx++) {
|
||||
int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
|
||||
if (documentCount > 0) {
|
||||
PropertyProto.Builder propertyBuilder =
|
||||
documentBuilder.getProperties(propertyIdx).toBuilder();
|
||||
for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
|
||||
DocumentProto.Builder derivedDocumentBuilder =
|
||||
propertyBuilder.getDocumentValues(documentIdx).toBuilder();
|
||||
addPrefixToDocument(derivedDocumentBuilder, prefix);
|
||||
propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
|
||||
}
|
||||
documentBuilder.setProperties(propertyIdx, propertyBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
|
||||
*
|
||||
* @param documentBuilder The document to mutate
|
||||
* @return Prefix name that was removed from the document.
|
||||
* @throws AppSearchException if there are unexpected database prefixing errors.
|
||||
*/
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
|
||||
throws AppSearchException {
|
||||
// Rewrite the type name and namespace to remove the prefix.
|
||||
String schemaPrefix = getPrefix(documentBuilder.getSchema());
|
||||
String namespacePrefix = getPrefix(documentBuilder.getNamespace());
|
||||
|
||||
if (!schemaPrefix.equals(namespacePrefix)) {
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_INTERNAL_ERROR,
|
||||
"Found unexpected"
|
||||
+ " multiple prefix names in document: "
|
||||
+ schemaPrefix
|
||||
+ ", "
|
||||
+ namespacePrefix);
|
||||
}
|
||||
|
||||
documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
|
||||
documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
|
||||
|
||||
// Recurse into derived documents
|
||||
for (int propertyIdx = 0;
|
||||
propertyIdx < documentBuilder.getPropertiesCount();
|
||||
propertyIdx++) {
|
||||
int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
|
||||
if (documentCount > 0) {
|
||||
PropertyProto.Builder propertyBuilder =
|
||||
documentBuilder.getProperties(propertyIdx).toBuilder();
|
||||
for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
|
||||
DocumentProto.Builder derivedDocumentBuilder =
|
||||
propertyBuilder.getDocumentValues(documentIdx).toBuilder();
|
||||
String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
|
||||
if (!nestedPrefix.equals(schemaPrefix)) {
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_INTERNAL_ERROR,
|
||||
"Found unexpected multiple prefix names in document: "
|
||||
+ schemaPrefix
|
||||
+ ", "
|
||||
+ nestedPrefix);
|
||||
}
|
||||
propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
|
||||
}
|
||||
documentBuilder.setProperties(propertyIdx, propertyBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
return schemaPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites the search spec filters with {@code prefixes}.
|
||||
*
|
||||
@@ -1443,9 +1372,9 @@ public final class AppSearchImpl implements Closeable {
|
||||
|
||||
if (allowedPrefixedSchemas.isEmpty()) {
|
||||
// If the client didn't specify any schema filters, search over all of their schemas
|
||||
Set<String> prefixedSchemas = mSchemaMapLocked.get(prefix);
|
||||
if (prefixedSchemas != null) {
|
||||
allowedPrefixedSchemas.addAll(prefixedSchemas);
|
||||
Map<String, SchemaTypeConfigProto> prefixedSchemaMap = mSchemaMapLocked.get(prefix);
|
||||
if (prefixedSchemaMap != null) {
|
||||
allowedPrefixedSchemas.addAll(prefixedSchemaMap.keySet());
|
||||
}
|
||||
}
|
||||
return allowedPrefixedSchemas;
|
||||
@@ -1656,86 +1585,6 @@ public final class AppSearchImpl implements Closeable {
|
||||
return mSchemaMapLocked.keySet();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
|
||||
return createPackagePrefix(packageName) + databaseName + DATABASE_DELIMITER;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String createPackagePrefix(@NonNull String packageName) {
|
||||
return packageName + PACKAGE_DELIMITER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package name that's contained within the {@code prefix}.
|
||||
*
|
||||
* @param prefix Prefix string that contains the package name inside of it. The package name
|
||||
* must be in the front of the string, and separated from the rest of the string by the
|
||||
* {@link #PACKAGE_DELIMITER}.
|
||||
* @return Valid package name.
|
||||
*/
|
||||
@NonNull
|
||||
private static String getPackageName(@NonNull String prefix) {
|
||||
int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
|
||||
if (delimiterIndex == -1) {
|
||||
// This should never happen if we construct our prefixes properly
|
||||
Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
|
||||
return "";
|
||||
}
|
||||
return prefix.substring(0, delimiterIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database name that's contained within the {@code prefix}.
|
||||
*
|
||||
* @param prefix Prefix string that contains the database name inside of it. The database name
|
||||
* must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
|
||||
* @return Valid database name.
|
||||
*/
|
||||
@NonNull
|
||||
private static String getDatabaseName(@NonNull String prefix) {
|
||||
int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
|
||||
int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
|
||||
if (packageDelimiterIndex == -1) {
|
||||
// This should never happen if we construct our prefixes properly
|
||||
Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
|
||||
return "";
|
||||
}
|
||||
if (databaseDelimiterIndex == -1) {
|
||||
// This should never happen if we construct our prefixes properly
|
||||
Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
|
||||
return "";
|
||||
}
|
||||
return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
|
||||
// The prefix is made up of the package, then the database. So we only need to find the
|
||||
// database cutoff.
|
||||
int delimiterIndex;
|
||||
if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
|
||||
// Add 1 to include the char size of the DATABASE_DELIMITER
|
||||
return prefixedString.substring(delimiterIndex + 1);
|
||||
}
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_UNKNOWN_ERROR,
|
||||
"The prefixed value doesn't contains a valid database name.");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
|
||||
int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
|
||||
if (databaseDelimiterIndex == -1) {
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_UNKNOWN_ERROR,
|
||||
"The databaseName prefixed value doesn't contain a valid database name.");
|
||||
}
|
||||
|
||||
// Add 1 to include the char size of the DATABASE_DELIMITER
|
||||
return prefixedString.substring(0, databaseDelimiterIndex + 1);
|
||||
}
|
||||
|
||||
private static void addToMap(
|
||||
Map<String, Set<String>> map, String prefix, String prefixedValue) {
|
||||
Set<String> values = map.get(prefix);
|
||||
@@ -1746,6 +1595,26 @@ public final class AppSearchImpl implements Closeable {
|
||||
values.add(prefixedValue);
|
||||
}
|
||||
|
||||
private static void addToMap(
|
||||
Map<String, Map<String, SchemaTypeConfigProto>> map,
|
||||
String prefix,
|
||||
SchemaTypeConfigProto schemaTypeConfigProto) {
|
||||
Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
|
||||
if (schemaTypeMap == null) {
|
||||
schemaTypeMap = new ArrayMap<>();
|
||||
map.put(prefix, schemaTypeMap);
|
||||
}
|
||||
schemaTypeMap.put(schemaTypeConfigProto.getSchemaType(), schemaTypeConfigProto);
|
||||
}
|
||||
|
||||
private static void removeFromMap(
|
||||
Map<String, Map<String, SchemaTypeConfigProto>> map, String prefix, String schemaType) {
|
||||
Map<String, SchemaTypeConfigProto> schemaTypeMap = map.get(prefix);
|
||||
if (schemaTypeMap != null) {
|
||||
schemaTypeMap.remove(schemaType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given status code and throws an {@link AppSearchException} if code is an error.
|
||||
*
|
||||
@@ -1853,7 +1722,9 @@ public final class AppSearchImpl implements Closeable {
|
||||
/** Remove the rewritten schema types from any result documents. */
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
static SearchResultPage rewriteSearchResultProto(@NonNull SearchResultProto searchResultProto)
|
||||
static SearchResultPage rewriteSearchResultProto(
|
||||
@NonNull SearchResultProto searchResultProto,
|
||||
@NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap)
|
||||
throws AppSearchException {
|
||||
// Parallel array of package names for each document search result.
|
||||
List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
|
||||
@@ -1873,7 +1744,7 @@ public final class AppSearchImpl implements Closeable {
|
||||
resultsBuilder.setResults(i, resultBuilder);
|
||||
}
|
||||
return SearchResultToProtoConverter.toSearchResultPage(
|
||||
resultsBuilder, packageNames, databaseNames);
|
||||
resultsBuilder, packageNames, databaseNames, schemaMap);
|
||||
}
|
||||
|
||||
@GuardedBy("mReadWriteLock")
|
||||
|
||||
@@ -18,11 +18,12 @@ package com.android.server.appsearch.external.localstorage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
|
||||
|
||||
import com.google.android.icing.proto.PutDocumentStatsProto;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class contains helper functions for logging.
|
||||
*
|
||||
@@ -42,8 +43,8 @@ public final class AppSearchLoggerHelper {
|
||||
static void copyNativeStats(
|
||||
@NonNull PutDocumentStatsProto fromNativeStats,
|
||||
@NonNull PutDocumentStats.Builder toStatsBuilder) {
|
||||
Preconditions.checkNotNull(fromNativeStats);
|
||||
Preconditions.checkNotNull(toStatsBuilder);
|
||||
Objects.requireNonNull(fromNativeStats);
|
||||
Objects.requireNonNull(toStatsBuilder);
|
||||
toStatsBuilder
|
||||
.setNativeLatencyMillis(fromNativeStats.getLatencyMs())
|
||||
.setNativeDocumentStoreLatencyMillis(fromNativeStats.getDocumentStoreLatencyMs())
|
||||
|
||||
@@ -17,16 +17,18 @@
|
||||
package com.android.server.appsearch.external.localstorage.converter;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.AppSearchSchema;
|
||||
import android.app.appsearch.GenericDocument;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import com.google.android.icing.proto.DocumentProto;
|
||||
import com.google.android.icing.proto.PropertyProto;
|
||||
import com.google.android.icing.proto.SchemaTypeConfigProto;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Translates a {@link GenericDocument} into a {@link DocumentProto}.
|
||||
@@ -34,13 +36,20 @@ import java.util.Collections;
|
||||
* @hide
|
||||
*/
|
||||
public final class GenericDocumentToProtoConverter {
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
private static final long[] EMPTY_LONG_ARRAY = new long[0];
|
||||
private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
|
||||
private static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
|
||||
private static final byte[][] EMPTY_BYTES_ARRAY = new byte[0][0];
|
||||
private static final GenericDocument[] EMPTY_DOCUMENT_ARRAY = new GenericDocument[0];
|
||||
|
||||
private GenericDocumentToProtoConverter() {}
|
||||
|
||||
/** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
|
||||
@NonNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public static DocumentProto toDocumentProto(@NonNull GenericDocument document) {
|
||||
Preconditions.checkNotNull(document);
|
||||
Objects.requireNonNull(document);
|
||||
DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
|
||||
mProtoBuilder
|
||||
.setUri(document.getUri())
|
||||
@@ -97,16 +106,34 @@ public final class GenericDocumentToProtoConverter {
|
||||
return mProtoBuilder.build();
|
||||
}
|
||||
|
||||
/** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
|
||||
/**
|
||||
* Converts a {@link DocumentProto} into a {@link GenericDocument}.
|
||||
*
|
||||
* <p>In the case that the {@link DocumentProto} object proto has no values set, the converter
|
||||
* searches for the matching property name in the {@link SchemaTypeConfigProto} object for the
|
||||
* document, and infers the correct default value to set for the empty property based on the
|
||||
* data type of the property defined by the schema type.
|
||||
*
|
||||
* @param proto the document to convert to a {@link GenericDocument} instance. The document
|
||||
* proto should have its package + database prefix stripped from its fields.
|
||||
* @param prefix the package + database prefix used searching the {@code schemaTypeMap}.
|
||||
* @param schemaTypeMap map of prefixed schema type to {@link SchemaTypeConfigProto}, used for
|
||||
* looking up the default empty value to set for a document property that has all empty
|
||||
* values.
|
||||
*/
|
||||
@NonNull
|
||||
public static GenericDocument toGenericDocument(@NonNull DocumentProto proto) {
|
||||
Preconditions.checkNotNull(proto);
|
||||
public static GenericDocument toGenericDocument(
|
||||
@NonNull DocumentProto proto,
|
||||
@NonNull String prefix,
|
||||
@NonNull Map<String, SchemaTypeConfigProto> schemaTypeMap) {
|
||||
Objects.requireNonNull(proto);
|
||||
GenericDocument.Builder<?> documentBuilder =
|
||||
new GenericDocument.Builder<>(
|
||||
proto.getNamespace(), proto.getUri(), proto.getSchema())
|
||||
.setScore(proto.getScore())
|
||||
.setTtlMillis(proto.getTtlMs())
|
||||
.setCreationTimestampMillis(proto.getCreationTimestampMs());
|
||||
String prefixedSchemaType = prefix + proto.getSchema();
|
||||
|
||||
for (int i = 0; i < proto.getPropertiesCount(); i++) {
|
||||
PropertyProto property = proto.getProperties(i);
|
||||
@@ -144,13 +171,51 @@ public final class GenericDocumentToProtoConverter {
|
||||
} else if (property.getDocumentValuesCount() > 0) {
|
||||
GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()];
|
||||
for (int j = 0; j < values.length; j++) {
|
||||
values[j] = toGenericDocument(property.getDocumentValues(j));
|
||||
values[j] =
|
||||
toGenericDocument(property.getDocumentValues(j), prefix, schemaTypeMap);
|
||||
}
|
||||
documentBuilder.setPropertyDocument(name, values);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown type of value: " + name);
|
||||
// TODO(b/184966497): Optimize by caching PropertyConfigProto
|
||||
setEmptyProperty(name, documentBuilder, schemaTypeMap.get(prefixedSchemaType));
|
||||
}
|
||||
}
|
||||
return documentBuilder.build();
|
||||
}
|
||||
|
||||
private static void setEmptyProperty(
|
||||
@NonNull String propertyName,
|
||||
@NonNull GenericDocument.Builder<?> documentBuilder,
|
||||
@NonNull SchemaTypeConfigProto schema) {
|
||||
@AppSearchSchema.PropertyConfig.DataType int dataType = 0;
|
||||
for (int i = 0; i < schema.getPropertiesCount(); ++i) {
|
||||
if (propertyName.equals(schema.getProperties(i).getPropertyName())) {
|
||||
dataType = schema.getProperties(i).getDataType().getNumber();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dataType) {
|
||||
case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
|
||||
documentBuilder.setPropertyString(propertyName, EMPTY_STRING_ARRAY);
|
||||
break;
|
||||
case AppSearchSchema.PropertyConfig.DATA_TYPE_INT64:
|
||||
documentBuilder.setPropertyLong(propertyName, EMPTY_LONG_ARRAY);
|
||||
break;
|
||||
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
|
||||
documentBuilder.setPropertyDouble(propertyName, EMPTY_DOUBLE_ARRAY);
|
||||
break;
|
||||
case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
|
||||
documentBuilder.setPropertyBoolean(propertyName, EMPTY_BOOLEAN_ARRAY);
|
||||
break;
|
||||
case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
|
||||
documentBuilder.setPropertyBytes(propertyName, EMPTY_BYTES_ARRAY);
|
||||
break;
|
||||
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
|
||||
documentBuilder.setPropertyDocument(propertyName, EMPTY_DOCUMENT_ARRAY);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown type of value: " + propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ import android.annotation.NonNull;
|
||||
import android.app.appsearch.AppSearchSchema;
|
||||
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;
|
||||
@@ -30,6 +28,7 @@ import com.google.android.icing.proto.StringIndexingConfig;
|
||||
import com.google.android.icing.proto.TermMatchType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Translates an {@link AppSearchSchema} into a {@link SchemaTypeConfigProto}.
|
||||
@@ -48,7 +47,7 @@ public final class SchemaToProtoConverter {
|
||||
@NonNull
|
||||
public static SchemaTypeConfigProto toSchemaTypeConfigProto(
|
||||
@NonNull AppSearchSchema schema, int version) {
|
||||
Preconditions.checkNotNull(schema);
|
||||
Objects.requireNonNull(schema);
|
||||
SchemaTypeConfigProto.Builder protoBuilder =
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.setSchemaType(schema.getSchemaType())
|
||||
@@ -64,7 +63,7 @@ public final class SchemaToProtoConverter {
|
||||
@NonNull
|
||||
private static PropertyConfigProto toPropertyConfigProto(
|
||||
@NonNull AppSearchSchema.PropertyConfig property) {
|
||||
Preconditions.checkNotNull(property);
|
||||
Objects.requireNonNull(property);
|
||||
PropertyConfigProto.Builder builder =
|
||||
PropertyConfigProto.newBuilder().setPropertyName(property.getName());
|
||||
|
||||
@@ -116,7 +115,7 @@ public final class SchemaToProtoConverter {
|
||||
*/
|
||||
@NonNull
|
||||
public static AppSearchSchema toAppSearchSchema(@NonNull SchemaTypeConfigProtoOrBuilder proto) {
|
||||
Preconditions.checkNotNull(proto);
|
||||
Objects.requireNonNull(proto);
|
||||
AppSearchSchema.Builder builder = new AppSearchSchema.Builder(proto.getSchemaType());
|
||||
List<PropertyConfigProto> properties = proto.getPropertiesList();
|
||||
for (int i = 0; i < properties.size(); i++) {
|
||||
@@ -129,7 +128,7 @@ public final class SchemaToProtoConverter {
|
||||
@NonNull
|
||||
private static AppSearchSchema.PropertyConfig toPropertyConfig(
|
||||
@NonNull PropertyConfigProto proto) {
|
||||
Preconditions.checkNotNull(proto);
|
||||
Objects.requireNonNull(proto);
|
||||
switch (proto.getDataType()) {
|
||||
case STRING:
|
||||
return toStringPropertyConfig(proto);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.appsearch.external.localstorage.converter;
|
||||
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.GenericDocument;
|
||||
import android.app.appsearch.SearchResult;
|
||||
@@ -24,6 +26,7 @@ import android.os.Bundle;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import com.google.android.icing.proto.SchemaTypeConfigProto;
|
||||
import com.google.android.icing.proto.SearchResultProto;
|
||||
import com.google.android.icing.proto.SearchResultProtoOrBuilder;
|
||||
import com.google.android.icing.proto.SnippetMatchProto;
|
||||
@@ -31,6 +34,7 @@ import com.google.android.icing.proto.SnippetProto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Translates a {@link SearchResultProto} into {@link SearchResult}s.
|
||||
@@ -49,13 +53,17 @@ public class SearchResultToProtoConverter {
|
||||
* @param databaseNames A parallel array of database names. The database name at index 'i' of
|
||||
* this list shold be the database that indexed the document at index 'i' of
|
||||
* proto.getResults(i).
|
||||
* @param schemaMap A map of prefixes to an inner-map of prefixed schema type to
|
||||
* SchemaTypeConfigProtos, used for setting a default value for results with DocumentProtos
|
||||
* that have empty values.
|
||||
* @return {@link SearchResultPage} of results.
|
||||
*/
|
||||
@NonNull
|
||||
public static SearchResultPage toSearchResultPage(
|
||||
@NonNull SearchResultProtoOrBuilder proto,
|
||||
@NonNull List<String> packageNames,
|
||||
@NonNull List<String> databaseNames) {
|
||||
@NonNull List<String> databaseNames,
|
||||
@NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap) {
|
||||
Preconditions.checkArgument(
|
||||
proto.getResultsCount() == packageNames.size(),
|
||||
"Size of results does not match the number of package names.");
|
||||
@@ -63,8 +71,14 @@ public class SearchResultToProtoConverter {
|
||||
bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
|
||||
ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
|
||||
for (int i = 0; i < proto.getResultsCount(); i++) {
|
||||
String prefix = createPrefix(packageNames.get(i), databaseNames.get(i));
|
||||
Map<String, SchemaTypeConfigProto> schemaTypeMap = schemaMap.get(prefix);
|
||||
SearchResult result =
|
||||
toSearchResult(proto.getResults(i), packageNames.get(i), databaseNames.get(i));
|
||||
toSearchResult(
|
||||
proto.getResults(i),
|
||||
packageNames.get(i),
|
||||
databaseNames.get(i),
|
||||
schemaTypeMap);
|
||||
resultBundles.add(result.getBundle());
|
||||
}
|
||||
bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
|
||||
@@ -77,15 +91,21 @@ public class SearchResultToProtoConverter {
|
||||
* @param proto The proto to be converted.
|
||||
* @param packageName The package name associated with the document in {@code proto}.
|
||||
* @param databaseName The database name associated with the document in {@code proto}.
|
||||
* @param schemaTypeToProtoMap A map of prefixed schema types to their corresponding
|
||||
* SchemaTypeConfigProto, used for setting a default value for results with DocumentProtos
|
||||
* that have empty values.
|
||||
* @return A {@link SearchResult} bundle.
|
||||
*/
|
||||
@NonNull
|
||||
private static SearchResult toSearchResult(
|
||||
@NonNull SearchResultProto.ResultProtoOrBuilder proto,
|
||||
@NonNull String packageName,
|
||||
@NonNull String databaseName) {
|
||||
@NonNull String databaseName,
|
||||
@NonNull Map<String, SchemaTypeConfigProto> schemaTypeToProtoMap) {
|
||||
String prefix = createPrefix(packageName, databaseName);
|
||||
GenericDocument document =
|
||||
GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
|
||||
GenericDocumentToProtoConverter.toGenericDocument(
|
||||
proto.getDocument(), prefix, schemaTypeToProtoMap);
|
||||
SearchResult.Builder builder =
|
||||
new SearchResult.Builder(packageName, databaseName)
|
||||
.setGenericDocument(document)
|
||||
|
||||
@@ -19,13 +19,13 @@ package com.android.server.appsearch.external.localstorage.converter;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.SearchSpec;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
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 java.util.Objects;
|
||||
|
||||
/**
|
||||
* Translates a {@link SearchSpec} into icing search protos.
|
||||
*
|
||||
@@ -37,7 +37,7 @@ public final class SearchSpecToProtoConverter {
|
||||
/** Extracts {@link SearchSpecProto} information from a {@link SearchSpec}. */
|
||||
@NonNull
|
||||
public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) {
|
||||
Preconditions.checkNotNull(spec);
|
||||
Objects.requireNonNull(spec);
|
||||
SearchSpecProto.Builder protoBuilder =
|
||||
SearchSpecProto.newBuilder()
|
||||
.addAllSchemaTypeFilters(spec.getFilterSchemas())
|
||||
@@ -56,7 +56,7 @@ public final class SearchSpecToProtoConverter {
|
||||
/** Extracts {@link ResultSpecProto} information from a {@link SearchSpec}. */
|
||||
@NonNull
|
||||
public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
|
||||
Preconditions.checkNotNull(spec);
|
||||
Objects.requireNonNull(spec);
|
||||
return ResultSpecProto.newBuilder()
|
||||
.setNumPerPage(spec.getResultCountPerPage())
|
||||
.setSnippetSpec(
|
||||
@@ -73,7 +73,7 @@ public final class SearchSpecToProtoConverter {
|
||||
/** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
|
||||
@NonNull
|
||||
public static ScoringSpecProto toScoringSpecProto(@NonNull SearchSpec spec) {
|
||||
Preconditions.checkNotNull(spec);
|
||||
Objects.requireNonNull(spec);
|
||||
ScoringSpecProto.Builder protoBuilder = ScoringSpecProto.newBuilder();
|
||||
|
||||
@SearchSpec.Order int orderCode = spec.getOrder();
|
||||
|
||||
@@ -19,10 +19,10 @@ package com.android.server.appsearch.external.localstorage.converter;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.SetSchemaResponse;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import com.google.android.icing.proto.SetSchemaResultProto;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Translates a {@link SetSchemaResultProto} into {@link SetSchemaResponse}.
|
||||
*
|
||||
@@ -42,8 +42,8 @@ public class SetSchemaResponseToProtoConverter {
|
||||
@NonNull
|
||||
public static SetSchemaResponse toSetSchemaResponse(
|
||||
@NonNull SetSchemaResultProto proto, @NonNull String prefix) {
|
||||
Preconditions.checkNotNull(proto);
|
||||
Preconditions.checkNotNull(prefix);
|
||||
Objects.requireNonNull(proto);
|
||||
Objects.requireNonNull(prefix);
|
||||
SetSchemaResponse.Builder builder = new SetSchemaResponse.Builder();
|
||||
|
||||
for (int i = 0; i < proto.getDeletedSchemaTypesCount(); i++) {
|
||||
|
||||
@@ -18,13 +18,12 @@ 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;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Translates a <code>Map<String, List<String>></code> into <code>List<TypePropertyMask></code>.
|
||||
@@ -38,7 +37,7 @@ public final class TypePropertyPathToProtoConverter {
|
||||
@NonNull
|
||||
public static List<TypePropertyMask> toTypePropertyMaskList(
|
||||
@NonNull Map<String, List<String>> typePropertyPaths) {
|
||||
Preconditions.checkNotNull(typePropertyPaths);
|
||||
Objects.requireNonNull(typePropertyPaths);
|
||||
List<TypePropertyMask> typePropertyMasks = new ArrayList<>(typePropertyPaths.size());
|
||||
for (Map.Entry<String, List<String>> e : typePropertyPaths.entrySet()) {
|
||||
typePropertyMasks.add(
|
||||
|
||||
@@ -19,10 +19,9 @@ package com.android.server.appsearch.external.localstorage.stats;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A class for setting basic information to log for all function calls.
|
||||
@@ -75,8 +74,8 @@ public class CallStats {
|
||||
private final int mNumOperationsFailed;
|
||||
|
||||
CallStats(@NonNull Builder builder) {
|
||||
Preconditions.checkNotNull(builder);
|
||||
mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
|
||||
Objects.requireNonNull(builder);
|
||||
mGeneralStats = Objects.requireNonNull(builder.mGeneralStatsBuilder).build();
|
||||
mCallType = builder.mCallType;
|
||||
mEstimatedBinderLatencyMillis = builder.mEstimatedBinderLatencyMillis;
|
||||
mNumOperationsSucceeded = builder.mNumOperationsSucceeded;
|
||||
@@ -140,8 +139,8 @@ public class CallStats {
|
||||
|
||||
/** Builder takes {@link GeneralStats.Builder}. */
|
||||
public Builder(@NonNull String packageName, @NonNull String database) {
|
||||
Preconditions.checkNotNull(packageName);
|
||||
Preconditions.checkNotNull(database);
|
||||
Objects.requireNonNull(packageName);
|
||||
Objects.requireNonNull(database);
|
||||
mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.android.server.appsearch.external.localstorage.stats;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A class for holding general logging information.
|
||||
@@ -48,9 +48,9 @@ public final class GeneralStats {
|
||||
private final int mTotalLatencyMillis;
|
||||
|
||||
GeneralStats(@NonNull Builder builder) {
|
||||
Preconditions.checkNotNull(builder);
|
||||
mPackageName = Preconditions.checkNotNull(builder.mPackageName);
|
||||
mDatabase = Preconditions.checkNotNull(builder.mDatabase);
|
||||
Objects.requireNonNull(builder);
|
||||
mPackageName = Objects.requireNonNull(builder.mPackageName);
|
||||
mDatabase = Objects.requireNonNull(builder.mDatabase);
|
||||
mStatusCode = builder.mStatusCode;
|
||||
mTotalLatencyMillis = builder.mTotalLatencyMillis;
|
||||
}
|
||||
@@ -92,8 +92,8 @@ public final class GeneralStats {
|
||||
* @param database name of the database logging stats
|
||||
*/
|
||||
public Builder(@NonNull String packageName, @NonNull String database) {
|
||||
mPackageName = Preconditions.checkNotNull(packageName);
|
||||
mDatabase = Preconditions.checkNotNull(database);
|
||||
mPackageName = Objects.requireNonNull(packageName);
|
||||
mDatabase = Objects.requireNonNull(database);
|
||||
}
|
||||
|
||||
/** Sets status code returned from {@link AppSearchResult#getResultCode()} */
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.android.server.appsearch.external.localstorage.stats;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A class for holding detailed stats to log for each individual document put by a {@link
|
||||
@@ -60,8 +60,8 @@ public final class PutDocumentStats {
|
||||
private final boolean mNativeExceededMaxNumTokens;
|
||||
|
||||
PutDocumentStats(@NonNull Builder builder) {
|
||||
Preconditions.checkNotNull(builder);
|
||||
mGeneralStats = Preconditions.checkNotNull(builder.mGeneralStatsBuilder).build();
|
||||
Objects.requireNonNull(builder);
|
||||
mGeneralStats = Objects.requireNonNull(builder.mGeneralStatsBuilder).build();
|
||||
mGenerateDocumentProtoLatencyMillis = builder.mGenerateDocumentProtoLatencyMillis;
|
||||
mRewriteDocumentTypesLatencyMillis = builder.mRewriteDocumentTypesLatencyMillis;
|
||||
mNativeLatencyMillis = builder.mNativeLatencyMillis;
|
||||
@@ -142,8 +142,8 @@ public final class PutDocumentStats {
|
||||
|
||||
/** Builder takes {@link GeneralStats.Builder}. */
|
||||
public Builder(@NonNull String packageName, @NonNull String database) {
|
||||
Preconditions.checkNotNull(packageName);
|
||||
Preconditions.checkNotNull(database);
|
||||
Objects.requireNonNull(packageName);
|
||||
Objects.requireNonNull(database);
|
||||
mGeneralStatsBuilder = new GeneralStats.Builder(packageName, database);
|
||||
}
|
||||
|
||||
|
||||
229
apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java
vendored
Normal file
229
apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/util/PrefixUtil.java
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import com.google.android.icing.proto.DocumentProto;
|
||||
import com.google.android.icing.proto.PropertyProto;
|
||||
|
||||
/**
|
||||
* Provides utility functions for working with package + database prefixes.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class PrefixUtil {
|
||||
private static final String TAG = "AppSearchPrefixUtil";
|
||||
|
||||
@VisibleForTesting public static final char DATABASE_DELIMITER = '/';
|
||||
|
||||
@VisibleForTesting public static final char PACKAGE_DELIMITER = '$';
|
||||
|
||||
private PrefixUtil() {}
|
||||
|
||||
/** Creates prefix string for given package name and database name. */
|
||||
@NonNull
|
||||
public static String createPrefix(@NonNull String packageName, @NonNull String databaseName) {
|
||||
return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
|
||||
}
|
||||
/** Creates prefix string for given package name. */
|
||||
@NonNull
|
||||
public static String createPackagePrefix(@NonNull String packageName) {
|
||||
return packageName + PACKAGE_DELIMITER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package name that's contained within the {@code prefix}.
|
||||
*
|
||||
* @param prefix Prefix string that contains the package name inside of it. The package name
|
||||
* must be in the front of the string, and separated from the rest of the string by the
|
||||
* {@link #PACKAGE_DELIMITER}.
|
||||
* @return Valid package name.
|
||||
*/
|
||||
@NonNull
|
||||
public static String getPackageName(@NonNull String prefix) {
|
||||
int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
|
||||
if (delimiterIndex == -1) {
|
||||
// This should never happen if we construct our prefixes properly
|
||||
Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
|
||||
return "";
|
||||
}
|
||||
return prefix.substring(0, delimiterIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database name that's contained within the {@code prefix}.
|
||||
*
|
||||
* @param prefix Prefix string that contains the database name inside of it. The database name
|
||||
* must be between the {@link #PACKAGE_DELIMITER} and {@link #DATABASE_DELIMITER}
|
||||
* @return Valid database name.
|
||||
*/
|
||||
@NonNull
|
||||
public static String getDatabaseName(@NonNull String prefix) {
|
||||
// TODO (b/184050178) Start database delimiter index search from after package delimiter
|
||||
int packageDelimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
|
||||
int databaseDelimiterIndex = prefix.indexOf(DATABASE_DELIMITER);
|
||||
if (packageDelimiterIndex == -1) {
|
||||
// This should never happen if we construct our prefixes properly
|
||||
Log.wtf(TAG, "Malformed prefix doesn't contain package delimiter: " + prefix);
|
||||
return "";
|
||||
}
|
||||
if (databaseDelimiterIndex == -1) {
|
||||
// This should never happen if we construct our prefixes properly
|
||||
Log.wtf(TAG, "Malformed prefix doesn't contain database delimiter: " + prefix);
|
||||
return "";
|
||||
}
|
||||
return prefix.substring(packageDelimiterIndex + 1, databaseDelimiterIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string with the package and database prefix removed from the input string.
|
||||
*
|
||||
* @param prefixedString a string containing a package and database prefix.
|
||||
* @return a string with the package and database prefix removed.
|
||||
* @throws AppSearchException if the prefixed value does not contain a valid database name.
|
||||
*/
|
||||
@NonNull
|
||||
public static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
|
||||
// The prefix is made up of the package, then the database. So we only need to find the
|
||||
// database cutoff.
|
||||
int delimiterIndex;
|
||||
if ((delimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER)) != -1) {
|
||||
// Add 1 to include the char size of the DATABASE_DELIMITER
|
||||
return prefixedString.substring(delimiterIndex + 1);
|
||||
}
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_UNKNOWN_ERROR,
|
||||
"The prefixed value doesn't contains a valid database name.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a package and database prefix string from the input string.
|
||||
*
|
||||
* @param prefixedString a string containing a package and database prefix.
|
||||
* @return a string with the package and database prefix
|
||||
* @throws AppSearchException if the prefixed value does not contain a valid database name.
|
||||
*/
|
||||
@NonNull
|
||||
public static String getPrefix(@NonNull String prefixedString) throws AppSearchException {
|
||||
int databaseDelimiterIndex = prefixedString.indexOf(DATABASE_DELIMITER);
|
||||
if (databaseDelimiterIndex == -1) {
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_UNKNOWN_ERROR,
|
||||
"The databaseName prefixed value doesn't contain a valid database name.");
|
||||
}
|
||||
|
||||
// Add 1 to include the char size of the DATABASE_DELIMITER
|
||||
return prefixedString.substring(0, databaseDelimiterIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends {@code prefix} to all types and namespaces mentioned anywhere in {@code
|
||||
* documentBuilder}.
|
||||
*
|
||||
* @param documentBuilder The document to mutate
|
||||
* @param prefix The prefix to add
|
||||
*/
|
||||
public static void addPrefixToDocument(
|
||||
@NonNull DocumentProto.Builder documentBuilder, @NonNull String prefix) {
|
||||
// Rewrite the type name to include/remove the prefix.
|
||||
String newSchema = prefix + documentBuilder.getSchema();
|
||||
documentBuilder.setSchema(newSchema);
|
||||
|
||||
// Rewrite the namespace to include/remove the prefix.
|
||||
documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
|
||||
|
||||
// Recurse into derived documents
|
||||
for (int propertyIdx = 0;
|
||||
propertyIdx < documentBuilder.getPropertiesCount();
|
||||
propertyIdx++) {
|
||||
int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
|
||||
if (documentCount > 0) {
|
||||
PropertyProto.Builder propertyBuilder =
|
||||
documentBuilder.getProperties(propertyIdx).toBuilder();
|
||||
for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
|
||||
DocumentProto.Builder derivedDocumentBuilder =
|
||||
propertyBuilder.getDocumentValues(documentIdx).toBuilder();
|
||||
addPrefixToDocument(derivedDocumentBuilder, prefix);
|
||||
propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
|
||||
}
|
||||
documentBuilder.setProperties(propertyIdx, propertyBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
|
||||
*
|
||||
* @param documentBuilder The document to mutate
|
||||
* @return Prefix name that was removed from the document.
|
||||
* @throws AppSearchException if there are unexpected database prefixing errors.
|
||||
*/
|
||||
@NonNull
|
||||
public static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
|
||||
throws AppSearchException {
|
||||
// Rewrite the type name and namespace to remove the prefix.
|
||||
String schemaPrefix = getPrefix(documentBuilder.getSchema());
|
||||
String namespacePrefix = getPrefix(documentBuilder.getNamespace());
|
||||
|
||||
if (!schemaPrefix.equals(namespacePrefix)) {
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_INTERNAL_ERROR,
|
||||
"Found unexpected"
|
||||
+ " multiple prefix names in document: "
|
||||
+ schemaPrefix
|
||||
+ ", "
|
||||
+ namespacePrefix);
|
||||
}
|
||||
|
||||
documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
|
||||
documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));
|
||||
|
||||
// Recurse into derived documents
|
||||
for (int propertyIdx = 0;
|
||||
propertyIdx < documentBuilder.getPropertiesCount();
|
||||
propertyIdx++) {
|
||||
int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
|
||||
if (documentCount > 0) {
|
||||
PropertyProto.Builder propertyBuilder =
|
||||
documentBuilder.getProperties(propertyIdx).toBuilder();
|
||||
for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
|
||||
DocumentProto.Builder derivedDocumentBuilder =
|
||||
propertyBuilder.getDocumentValues(documentIdx).toBuilder();
|
||||
String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
|
||||
if (!nestedPrefix.equals(schemaPrefix)) {
|
||||
throw new AppSearchException(
|
||||
AppSearchResult.RESULT_INTERNAL_ERROR,
|
||||
"Found unexpected multiple prefix names in document: "
|
||||
+ schemaPrefix
|
||||
+ ", "
|
||||
+ nestedPrefix);
|
||||
}
|
||||
propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
|
||||
}
|
||||
documentBuilder.setProperties(propertyIdx, propertyBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
return schemaPrefix;
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
I925ec12f4901c7759976c344ba3428210aada8ad
|
||||
If9d1d770d2327d7d0db7d82acfc54787b5de64bc
|
||||
|
||||
@@ -187,9 +187,8 @@ public interface AppSearchSessionShim extends Closeable {
|
||||
* <p>Removed documents will no longer be surfaced by {@link #search} or {@link #getByUri}
|
||||
* calls.
|
||||
*
|
||||
* <p><b>NOTE:</b>By default, documents are removed via a soft delete operation. Once the
|
||||
* document crosses the count threshold or byte usage threshold, the documents will be removed
|
||||
* from disk.
|
||||
* <p>Once the database crosses the document count or byte usage threshold, removed documents
|
||||
* will be deleted from disk.
|
||||
*
|
||||
* @param request {@link RemoveByUriRequest} with URIs and namespace to remove from the index.
|
||||
* @return a {@link ListenableFuture} which resolves to an {@link AppSearchBatchResult}. The
|
||||
|
||||
41
core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
vendored
Normal file
41
core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 org.junit.Test;
|
||||
|
||||
public class AppSearchResultTest {
|
||||
@Test
|
||||
public void testMapNullPointerException() {
|
||||
NullPointerException e =
|
||||
expectThrows(
|
||||
NullPointerException.class,
|
||||
() -> {
|
||||
Object o = null;
|
||||
o.toString();
|
||||
});
|
||||
AppSearchResult<?> result = AppSearchResult.throwableToFailedResult(e);
|
||||
assertThat(result.getResultCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
|
||||
// Makes sure the exception name is included in the string. Some exceptions have terse or
|
||||
// missing strings so it's confusing to read the output without the exception name.
|
||||
assertThat(result.getErrorMessage()).startsWith("NullPointerException");
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,8 @@ import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
@@ -203,7 +205,7 @@ public class AppSearchImplPlatformTest {
|
||||
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
|
||||
|
||||
// Set schema1
|
||||
String prefix = AppSearchImpl.createPrefix("package", "database");
|
||||
String prefix = PrefixUtil.createPrefix("package", "database");
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
@@ -280,7 +282,7 @@ public class AppSearchImplPlatformTest {
|
||||
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
|
||||
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
|
||||
|
||||
String prefix = AppSearchImpl.createPrefix("package", "database");
|
||||
String prefix = PrefixUtil.createPrefix("package", "database");
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
@@ -353,7 +355,7 @@ public class AppSearchImplPlatformTest {
|
||||
|
||||
@Test
|
||||
public void testSetSchema_defaultPlatformVisible() throws Exception {
|
||||
String prefix = AppSearchImpl.createPrefix("package", "database");
|
||||
String prefix = PrefixUtil.createPrefix("package", "database");
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
@@ -372,7 +374,7 @@ public class AppSearchImplPlatformTest {
|
||||
|
||||
@Test
|
||||
public void testSetSchema_platformHidden() throws Exception {
|
||||
String prefix = AppSearchImpl.createPrefix("package", "database");
|
||||
String prefix = PrefixUtil.createPrefix("package", "database");
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
@@ -391,7 +393,7 @@ public class AppSearchImplPlatformTest {
|
||||
|
||||
@Test
|
||||
public void testSetSchema_defaultNotPackageAccessible() throws Exception {
|
||||
String prefix = AppSearchImpl.createPrefix("package", "database");
|
||||
String prefix = PrefixUtil.createPrefix("package", "database");
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
@@ -419,7 +421,7 @@ public class AppSearchImplPlatformTest {
|
||||
mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
|
||||
mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
|
||||
|
||||
String prefix = AppSearchImpl.createPrefix("package", "database");
|
||||
String prefix = PrefixUtil.createPrefix("package", "database");
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
|
||||
@@ -28,6 +28,8 @@ import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -78,13 +80,9 @@ public class VisibilityStoreTest {
|
||||
@Test
|
||||
public void testValidPackageName() {
|
||||
assertThat(VisibilityStore.PACKAGE_NAME)
|
||||
.doesNotContain(
|
||||
"" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
|
||||
.doesNotContain(String.valueOf(PrefixUtil.PACKAGE_DELIMITER));
|
||||
assertThat(VisibilityStore.PACKAGE_NAME)
|
||||
.doesNotContain(
|
||||
""
|
||||
+ AppSearchImpl
|
||||
.DATABASE_DELIMITER); // Convert the chars to CharSequences
|
||||
.doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,13 +91,9 @@ public class VisibilityStoreTest {
|
||||
@Test
|
||||
public void testValidDatabaseName() {
|
||||
assertThat(VisibilityStore.DATABASE_NAME)
|
||||
.doesNotContain(
|
||||
"" + AppSearchImpl.PACKAGE_DELIMITER); // Convert the chars to CharSequences
|
||||
.doesNotContain(String.valueOf(PrefixUtil.PACKAGE_DELIMITER));
|
||||
assertThat(VisibilityStore.DATABASE_NAME)
|
||||
.doesNotContain(
|
||||
""
|
||||
+ AppSearchImpl
|
||||
.DATABASE_DELIMITER); // Convert the chars to CharSequences
|
||||
.doesNotContain(String.valueOf(PrefixUtil.DATABASE_DELIMITER));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.server.appsearch.external.localstorage;
|
||||
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.addPrefixToDocument;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.createPrefix;
|
||||
import static com.android.server.appsearch.external.localstorage.util.PrefixUtil.removePrefixesFromDocument;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.expectThrows;
|
||||
@@ -35,8 +39,10 @@ import android.util.ArraySet;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
|
||||
import com.android.server.appsearch.proto.DocumentProto;
|
||||
import com.android.server.appsearch.proto.GetOptimizeInfoResultProto;
|
||||
import com.android.server.appsearch.proto.PersistType;
|
||||
import com.android.server.appsearch.proto.PropertyConfigProto;
|
||||
import com.android.server.appsearch.proto.PropertyProto;
|
||||
import com.android.server.appsearch.proto.SchemaProto;
|
||||
@@ -47,6 +53,7 @@ import com.android.server.appsearch.proto.StringIndexingConfig;
|
||||
import com.android.server.appsearch.proto.TermMatchType;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -54,6 +61,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -96,56 +104,71 @@ public class AppSearchImplTest {
|
||||
// Create a copy so we can modify it.
|
||||
List<SchemaTypeConfigProto> existingTypes =
|
||||
new ArrayList<>(existingSchemaBuilder.getTypesList());
|
||||
|
||||
SchemaProto newSchema =
|
||||
SchemaProto.newBuilder()
|
||||
.addTypes(SchemaTypeConfigProto.newBuilder().setSchemaType("Foo").build())
|
||||
.addTypes(
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.setSchemaType("TestType")
|
||||
.addProperties(
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setPropertyName("subject")
|
||||
.setDataType(
|
||||
PropertyConfigProto.DataType.Code
|
||||
.STRING)
|
||||
.setCardinality(
|
||||
PropertyConfigProto.Cardinality.Code
|
||||
.OPTIONAL)
|
||||
.setStringIndexingConfig(
|
||||
StringIndexingConfig.newBuilder()
|
||||
.setTokenizerType(
|
||||
StringIndexingConfig
|
||||
.TokenizerType
|
||||
.Code.PLAIN)
|
||||
.setTermMatchType(
|
||||
TermMatchType.Code
|
||||
.PREFIX)
|
||||
.build())
|
||||
.build())
|
||||
.addProperties(
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setPropertyName("link")
|
||||
.setDataType(
|
||||
PropertyConfigProto.DataType.Code
|
||||
.DOCUMENT)
|
||||
.setCardinality(
|
||||
PropertyConfigProto.Cardinality.Code
|
||||
.OPTIONAL)
|
||||
.setSchemaType("RefType")
|
||||
SchemaTypeConfigProto schemaTypeConfigProto1 =
|
||||
SchemaTypeConfigProto.newBuilder().setSchemaType("Foo").build();
|
||||
SchemaTypeConfigProto schemaTypeConfigProto2 =
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.setSchemaType("TestType")
|
||||
.addProperties(
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setPropertyName("subject")
|
||||
.setDataType(PropertyConfigProto.DataType.Code.STRING)
|
||||
.setCardinality(
|
||||
PropertyConfigProto.Cardinality.Code.OPTIONAL)
|
||||
.setStringIndexingConfig(
|
||||
StringIndexingConfig.newBuilder()
|
||||
.setTokenizerType(
|
||||
StringIndexingConfig.TokenizerType
|
||||
.Code.PLAIN)
|
||||
.setTermMatchType(TermMatchType.Code.PREFIX)
|
||||
.build())
|
||||
.build())
|
||||
.addProperties(
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setPropertyName("link")
|
||||
.setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
|
||||
.setCardinality(
|
||||
PropertyConfigProto.Cardinality.Code.OPTIONAL)
|
||||
.setSchemaType("RefType")
|
||||
.build())
|
||||
.build();
|
||||
SchemaTypeConfigProto schemaTypeConfigProto3 =
|
||||
SchemaTypeConfigProto.newBuilder().setSchemaType("RefType").build();
|
||||
SchemaProto newSchema =
|
||||
SchemaProto.newBuilder()
|
||||
.addTypes(schemaTypeConfigProto1)
|
||||
.addTypes(schemaTypeConfigProto2)
|
||||
.addTypes(schemaTypeConfigProto3)
|
||||
.build();
|
||||
|
||||
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
|
||||
mAppSearchImpl.rewriteSchema(
|
||||
AppSearchImpl.createPrefix("package", "newDatabase"),
|
||||
existingSchemaBuilder,
|
||||
newSchema);
|
||||
createPrefix("package", "newDatabase"), existingSchemaBuilder, newSchema);
|
||||
|
||||
// We rewrote all the new types that were added. And nothing was removed.
|
||||
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
|
||||
.containsExactly("package$newDatabase/Foo", "package$newDatabase/TestType");
|
||||
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet())
|
||||
.containsExactly(
|
||||
"package$newDatabase/Foo",
|
||||
"package$newDatabase/TestType",
|
||||
"package$newDatabase/RefType");
|
||||
assertThat(
|
||||
rewrittenSchemaResults
|
||||
.mRewrittenPrefixedTypes
|
||||
.get("package$newDatabase/Foo")
|
||||
.getSchemaType())
|
||||
.isEqualTo("package$newDatabase/Foo");
|
||||
assertThat(
|
||||
rewrittenSchemaResults
|
||||
.mRewrittenPrefixedTypes
|
||||
.get("package$newDatabase/TestType")
|
||||
.getSchemaType())
|
||||
.isEqualTo("package$newDatabase/TestType");
|
||||
assertThat(
|
||||
rewrittenSchemaResults
|
||||
.mRewrittenPrefixedTypes
|
||||
.get("package$newDatabase/RefType")
|
||||
.getSchemaType())
|
||||
.isEqualTo("package$newDatabase/RefType");
|
||||
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
|
||||
|
||||
SchemaProto expectedSchema =
|
||||
@@ -190,6 +213,10 @@ public class AppSearchImplTest {
|
||||
"package$newDatabase/RefType")
|
||||
.build())
|
||||
.build())
|
||||
.addTypes(
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.setSchemaType("package$newDatabase/RefType")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
existingTypes.addAll(expectedSchema.getTypesList());
|
||||
@@ -216,12 +243,12 @@ public class AppSearchImplTest {
|
||||
|
||||
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
|
||||
mAppSearchImpl.rewriteSchema(
|
||||
AppSearchImpl.createPrefix("package", "existingDatabase"),
|
||||
createPrefix("package", "existingDatabase"),
|
||||
existingSchemaBuilder,
|
||||
newSchema);
|
||||
|
||||
// Nothing was removed, but the method did rewrite the type name.
|
||||
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
|
||||
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet())
|
||||
.containsExactly("package$existingDatabase/Foo");
|
||||
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes).isEmpty();
|
||||
|
||||
@@ -251,14 +278,15 @@ public class AppSearchImplTest {
|
||||
|
||||
AppSearchImpl.RewrittenSchemaResults rewrittenSchemaResults =
|
||||
mAppSearchImpl.rewriteSchema(
|
||||
AppSearchImpl.createPrefix("package", "existingDatabase"),
|
||||
createPrefix("package", "existingDatabase"),
|
||||
existingSchemaBuilder,
|
||||
newSchema);
|
||||
|
||||
// Bar type was rewritten, but Foo ended up being deleted since it wasn't included in the
|
||||
// new schema.
|
||||
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes)
|
||||
.containsExactly("package$existingDatabase/Bar");
|
||||
.containsKey("package$existingDatabase/Bar");
|
||||
assertThat(rewrittenSchemaResults.mRewrittenPrefixedTypes.keySet().size()).isEqualTo(1);
|
||||
assertThat(rewrittenSchemaResults.mDeletedPrefixedTypes)
|
||||
.containsExactly("package$existingDatabase/Foo");
|
||||
|
||||
@@ -308,8 +336,7 @@ public class AppSearchImplTest {
|
||||
.build();
|
||||
|
||||
DocumentProto.Builder actualDocument = documentProto.toBuilder();
|
||||
mAppSearchImpl.addPrefixToDocument(
|
||||
actualDocument, AppSearchImpl.createPrefix("package", "databaseName"));
|
||||
addPrefixToDocument(actualDocument, createPrefix("package", "databaseName"));
|
||||
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
|
||||
}
|
||||
|
||||
@@ -347,8 +374,7 @@ public class AppSearchImplTest {
|
||||
.build();
|
||||
|
||||
DocumentProto.Builder actualDocument = documentProto.toBuilder();
|
||||
assertThat(mAppSearchImpl.removePrefixesFromDocument(actualDocument))
|
||||
.isEqualTo("package$databaseName/");
|
||||
assertThat(removePrefixesFromDocument(actualDocument)).isEqualTo("package$databaseName/");
|
||||
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
|
||||
}
|
||||
|
||||
@@ -365,8 +391,7 @@ public class AppSearchImplTest {
|
||||
DocumentProto.Builder actualDocument = documentProto.toBuilder();
|
||||
AppSearchException e =
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
|
||||
AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
|
||||
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
|
||||
}
|
||||
|
||||
@@ -391,8 +416,7 @@ public class AppSearchImplTest {
|
||||
DocumentProto.Builder actualDocument = documentProto.toBuilder();
|
||||
AppSearchException e =
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
|
||||
AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
|
||||
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
|
||||
}
|
||||
|
||||
@@ -484,7 +508,7 @@ public class AppSearchImplTest {
|
||||
// Rewrite SearchSpec
|
||||
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
|
||||
searchSpecProto,
|
||||
Collections.singleton(AppSearchImpl.createPrefix("package", "database")),
|
||||
Collections.singleton(createPrefix("package", "database")),
|
||||
ImmutableSet.of("package$database/type"));
|
||||
assertThat(searchSpecProto.getSchemaTypeFiltersList())
|
||||
.containsExactly("package$database/type");
|
||||
@@ -531,8 +555,7 @@ public class AppSearchImplTest {
|
||||
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
|
||||
searchSpecProto,
|
||||
ImmutableSet.of(
|
||||
AppSearchImpl.createPrefix("package", "database1"),
|
||||
AppSearchImpl.createPrefix("package", "database2")),
|
||||
createPrefix("package", "database1"), createPrefix("package", "database2")),
|
||||
ImmutableSet.of(
|
||||
"package$database1/typeA", "package$database1/typeB",
|
||||
"package$database2/typeA", "package$database2/typeB"));
|
||||
@@ -573,8 +596,7 @@ public class AppSearchImplTest {
|
||||
assertThat(
|
||||
mAppSearchImpl.rewriteSearchSpecForPrefixesLocked(
|
||||
searchSpecProto,
|
||||
Collections.singleton(
|
||||
AppSearchImpl.createPrefix("package", "database")),
|
||||
Collections.singleton(createPrefix("package", "database")),
|
||||
/*allowedPrefixedSchemas=*/ Collections.emptySet()))
|
||||
.isFalse();
|
||||
}
|
||||
@@ -1082,7 +1104,7 @@ public class AppSearchImplTest {
|
||||
|
||||
// Has database1
|
||||
Set<String> expectedPrefixes = new ArraySet<>(existingPrefixes);
|
||||
expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database1"));
|
||||
expectedPrefixes.add(createPrefix("package", "database1"));
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database1",
|
||||
@@ -1094,7 +1116,7 @@ public class AppSearchImplTest {
|
||||
assertThat(mAppSearchImpl.getPrefixesLocked()).containsExactlyElementsIn(expectedPrefixes);
|
||||
|
||||
// Has both databases
|
||||
expectedPrefixes.add(AppSearchImpl.createPrefix("package", "database2"));
|
||||
expectedPrefixes.add(createPrefix("package", "database2"));
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database2",
|
||||
@@ -1110,9 +1132,9 @@ public class AppSearchImplTest {
|
||||
public void testRewriteSearchResultProto() throws Exception {
|
||||
final String prefix =
|
||||
"com.package.foo"
|
||||
+ AppSearchImpl.PACKAGE_DELIMITER
|
||||
+ PrefixUtil.PACKAGE_DELIMITER
|
||||
+ "databaseName"
|
||||
+ AppSearchImpl.DATABASE_DELIMITER;
|
||||
+ PrefixUtil.DATABASE_DELIMITER;
|
||||
final String uri = "uri";
|
||||
final String namespace = prefix + "namespace";
|
||||
final String schemaType = prefix + "schema";
|
||||
@@ -1128,18 +1150,22 @@ public class AppSearchImplTest {
|
||||
SearchResultProto.ResultProto.newBuilder().setDocument(documentProto).build();
|
||||
SearchResultProto searchResultProto =
|
||||
SearchResultProto.newBuilder().addResults(resultProto).build();
|
||||
SchemaTypeConfigProto schemaTypeConfigProto =
|
||||
SchemaTypeConfigProto.newBuilder().setSchemaType(schemaType).build();
|
||||
Map<String, Map<String, SchemaTypeConfigProto>> schemaMap =
|
||||
ImmutableMap.of(prefix, ImmutableMap.of(schemaType, schemaTypeConfigProto));
|
||||
|
||||
DocumentProto.Builder strippedDocumentProto = documentProto.toBuilder();
|
||||
AppSearchImpl.removePrefixesFromDocument(strippedDocumentProto);
|
||||
removePrefixesFromDocument(strippedDocumentProto);
|
||||
SearchResultPage searchResultPage =
|
||||
AppSearchImpl.rewriteSearchResultProto(searchResultProto);
|
||||
AppSearchImpl.rewriteSearchResultProto(searchResultProto, schemaMap);
|
||||
for (SearchResult result : searchResultPage.getResults()) {
|
||||
assertThat(result.getPackageName()).isEqualTo("com.package.foo");
|
||||
assertThat(result.getDatabaseName()).isEqualTo("databaseName");
|
||||
assertThat(result.getGenericDocument())
|
||||
.isEqualTo(
|
||||
GenericDocumentToProtoConverter.toGenericDocument(
|
||||
strippedDocumentProto.build()));
|
||||
strippedDocumentProto.build(), prefix, schemaMap.get(prefix)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1609,7 +1635,221 @@ public class AppSearchImplTest {
|
||||
expectThrows(
|
||||
IllegalStateException.class,
|
||||
() -> {
|
||||
appSearchImpl.persistToDisk();
|
||||
appSearchImpl.persistToDisk(PersistType.Code.FULL);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutPersistsWithLiteFlush() throws Exception {
|
||||
// Setup the index
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
File appsearchDir = mTemporaryFolder.newFolder();
|
||||
AppSearchImpl appSearchImpl =
|
||||
AppSearchImpl.create(
|
||||
appsearchDir,
|
||||
context,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage=*/ "");
|
||||
|
||||
List<AppSearchSchema> schemas =
|
||||
Collections.singletonList(new AppSearchSchema.Builder("type").build());
|
||||
appSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
schemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ false,
|
||||
/*version=*/ 0);
|
||||
|
||||
// Add a document and persist it.
|
||||
GenericDocument document =
|
||||
new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
|
||||
appSearchImpl.putDocument("package", "database", document, /*logger=*/ null);
|
||||
appSearchImpl.persistToDisk(PersistType.Code.LITE);
|
||||
|
||||
GenericDocument getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace1", "uri1", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document);
|
||||
|
||||
// That document should be visible even from another instance.
|
||||
AppSearchImpl appSearchImpl2 =
|
||||
AppSearchImpl.create(
|
||||
appsearchDir,
|
||||
context,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage=*/ "");
|
||||
getResult =
|
||||
appSearchImpl2.getDocument(
|
||||
"package", "database", "namespace1", "uri1", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletePersistsWithLiteFlush() throws Exception {
|
||||
// Setup the index
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
File appsearchDir = mTemporaryFolder.newFolder();
|
||||
AppSearchImpl appSearchImpl =
|
||||
AppSearchImpl.create(
|
||||
appsearchDir,
|
||||
context,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage=*/ "");
|
||||
|
||||
List<AppSearchSchema> schemas =
|
||||
Collections.singletonList(new AppSearchSchema.Builder("type").build());
|
||||
appSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
schemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ false,
|
||||
/*version=*/ 0);
|
||||
|
||||
// Add two documents and persist them.
|
||||
GenericDocument document1 =
|
||||
new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
|
||||
appSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
|
||||
GenericDocument document2 =
|
||||
new GenericDocument.Builder<>("namespace1", "uri2", "type").build();
|
||||
appSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
|
||||
appSearchImpl.persistToDisk(PersistType.Code.LITE);
|
||||
|
||||
GenericDocument getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace1", "uri1", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document1);
|
||||
getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace1", "uri2", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document2);
|
||||
|
||||
// Delete the first document
|
||||
appSearchImpl.remove("package", "database", "namespace1", "uri1");
|
||||
appSearchImpl.persistToDisk(PersistType.Code.LITE);
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() ->
|
||||
appSearchImpl.getDocument(
|
||||
"package",
|
||||
"database",
|
||||
"namespace1",
|
||||
"uri1",
|
||||
Collections.emptyMap()));
|
||||
getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace1", "uri2", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document2);
|
||||
|
||||
// Only the second document should be retrievable from another instance.
|
||||
AppSearchImpl appSearchImpl2 =
|
||||
AppSearchImpl.create(
|
||||
appsearchDir,
|
||||
context,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage=*/ "");
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() ->
|
||||
appSearchImpl2.getDocument(
|
||||
"package",
|
||||
"database",
|
||||
"namespace1",
|
||||
"uri1",
|
||||
Collections.emptyMap()));
|
||||
getResult =
|
||||
appSearchImpl2.getDocument(
|
||||
"package", "database", "namespace1", "uri2", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteByQueryPersistsWithLiteFlush() throws Exception {
|
||||
// Setup the index
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
File appsearchDir = mTemporaryFolder.newFolder();
|
||||
AppSearchImpl appSearchImpl =
|
||||
AppSearchImpl.create(
|
||||
appsearchDir,
|
||||
context,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage=*/ "");
|
||||
|
||||
List<AppSearchSchema> schemas =
|
||||
Collections.singletonList(new AppSearchSchema.Builder("type").build());
|
||||
appSearchImpl.setSchema(
|
||||
"package",
|
||||
"database",
|
||||
schemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ false,
|
||||
/*version=*/ 0);
|
||||
|
||||
// Add two documents and persist them.
|
||||
GenericDocument document1 =
|
||||
new GenericDocument.Builder<>("namespace1", "uri1", "type").build();
|
||||
appSearchImpl.putDocument("package", "database", document1, /*logger=*/ null);
|
||||
GenericDocument document2 =
|
||||
new GenericDocument.Builder<>("namespace2", "uri2", "type").build();
|
||||
appSearchImpl.putDocument("package", "database", document2, /*logger=*/ null);
|
||||
appSearchImpl.persistToDisk(PersistType.Code.LITE);
|
||||
|
||||
GenericDocument getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace1", "uri1", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document1);
|
||||
getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace2", "uri2", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document2);
|
||||
|
||||
// Delete the first document
|
||||
appSearchImpl.removeByQuery(
|
||||
"package",
|
||||
"database",
|
||||
"",
|
||||
new SearchSpec.Builder()
|
||||
.addFilterNamespaces("namespace1")
|
||||
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
|
||||
.build());
|
||||
appSearchImpl.persistToDisk(PersistType.Code.LITE);
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() ->
|
||||
appSearchImpl.getDocument(
|
||||
"package",
|
||||
"database",
|
||||
"namespace1",
|
||||
"uri1",
|
||||
Collections.emptyMap()));
|
||||
getResult =
|
||||
appSearchImpl.getDocument(
|
||||
"package", "database", "namespace2", "uri2", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document2);
|
||||
|
||||
// Only the second document should be retrievable from another instance.
|
||||
AppSearchImpl appSearchImpl2 =
|
||||
AppSearchImpl.create(
|
||||
appsearchDir,
|
||||
context,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage=*/ "");
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() ->
|
||||
appSearchImpl2.getDocument(
|
||||
"package",
|
||||
"database",
|
||||
"namespace1",
|
||||
"uri1",
|
||||
Collections.emptyMap()));
|
||||
getResult =
|
||||
appSearchImpl2.getDocument(
|
||||
"package", "database", "namespace2", "uri2", Collections.emptyMap());
|
||||
assertThat(getResult).isEqualTo(document2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,35 +21,50 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import android.app.appsearch.GenericDocument;
|
||||
|
||||
import com.android.server.appsearch.proto.DocumentProto;
|
||||
import com.android.server.appsearch.proto.PropertyConfigProto;
|
||||
import com.android.server.appsearch.proto.PropertyProto;
|
||||
import com.android.server.appsearch.proto.SchemaTypeConfigProto;
|
||||
import com.android.server.appsearch.protobuf.ByteString;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class GenericDocumentToProtoConverterTest {
|
||||
private static final byte[] BYTE_ARRAY_1 = new byte[] {(byte) 1, (byte) 2, (byte) 3};
|
||||
private static final byte[] BYTE_ARRAY_2 = new byte[] {(byte) 4, (byte) 5, (byte) 6, (byte) 7};
|
||||
private static final String SCHEMA_TYPE_1 = "sDocumentPropertiesSchemaType1";
|
||||
private static final String SCHEMA_TYPE_2 = "sDocumentPropertiesSchemaType2";
|
||||
private static final GenericDocument DOCUMENT_PROPERTIES_1 =
|
||||
new GenericDocument.Builder<GenericDocument.Builder<?>>(
|
||||
"namespace", "sDocumentProperties1", "sDocumentPropertiesSchemaType1")
|
||||
"namespace", "sDocumentProperties1", SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMillis(12345L)
|
||||
.build();
|
||||
private static final GenericDocument DOCUMENT_PROPERTIES_2 =
|
||||
new GenericDocument.Builder<GenericDocument.Builder<?>>(
|
||||
"namespace", "sDocumentProperties2", "sDocumentPropertiesSchemaType2")
|
||||
"namespace", "sDocumentProperties2", SCHEMA_TYPE_2)
|
||||
.setCreationTimestampMillis(6789L)
|
||||
.build();
|
||||
private static final SchemaTypeConfigProto SCHEMA_PROTO_1 =
|
||||
SchemaTypeConfigProto.newBuilder().setSchemaType(SCHEMA_TYPE_1).build();
|
||||
private static final SchemaTypeConfigProto SCHEMA_PROTO_2 =
|
||||
SchemaTypeConfigProto.newBuilder().setSchemaType(SCHEMA_TYPE_2).build();
|
||||
private static final String PREFIX = "package$databaseName/";
|
||||
private static final Map<String, SchemaTypeConfigProto> SCHEMA_MAP =
|
||||
ImmutableMap.of(
|
||||
PREFIX + SCHEMA_TYPE_1, SCHEMA_PROTO_1, PREFIX + SCHEMA_TYPE_2, SCHEMA_PROTO_2);
|
||||
|
||||
@Test
|
||||
public void testDocumentProtoConvert() {
|
||||
GenericDocument document =
|
||||
new GenericDocument.Builder<GenericDocument.Builder<?>>(
|
||||
"namespace", "uri1", "schemaType1")
|
||||
"namespace", "uri1", SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMillis(5L)
|
||||
.setScore(1)
|
||||
.setTtlMillis(1L)
|
||||
@@ -66,7 +81,7 @@ public class GenericDocumentToProtoConverterTest {
|
||||
DocumentProto.Builder documentProtoBuilder =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri("uri1")
|
||||
.setSchema("schemaType1")
|
||||
.setSchema(SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMs(5L)
|
||||
.setScore(1)
|
||||
.setTtlMs(1L)
|
||||
@@ -109,9 +124,133 @@ public class GenericDocumentToProtoConverterTest {
|
||||
documentProtoBuilder.addProperties(propertyProtoMap.get(key));
|
||||
}
|
||||
DocumentProto documentProto = documentProtoBuilder.build();
|
||||
assertThat(GenericDocumentToProtoConverter.toDocumentProto(document))
|
||||
.isEqualTo(documentProto);
|
||||
assertThat(document)
|
||||
.isEqualTo(GenericDocumentToProtoConverter.toGenericDocument(documentProto));
|
||||
|
||||
GenericDocument convertedGenericDocument =
|
||||
GenericDocumentToProtoConverter.toGenericDocument(
|
||||
documentProto, PREFIX, SCHEMA_MAP);
|
||||
DocumentProto convertedDocumentProto =
|
||||
GenericDocumentToProtoConverter.toDocumentProto(document);
|
||||
|
||||
assertThat(convertedDocumentProto).isEqualTo(documentProto);
|
||||
assertThat(convertedGenericDocument).isEqualTo(document);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertDocument_whenPropertyHasEmptyList() {
|
||||
String emptyStringPropertyName = "emptyStringProperty";
|
||||
DocumentProto documentProto =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri("uri1")
|
||||
.setSchema(SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMs(5L)
|
||||
.setNamespace("namespace")
|
||||
.addProperties(
|
||||
PropertyProto.newBuilder().setName(emptyStringPropertyName).build())
|
||||
.build();
|
||||
|
||||
PropertyConfigProto emptyStringListProperty =
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
|
||||
.setDataType(PropertyConfigProto.DataType.Code.STRING)
|
||||
.setPropertyName(emptyStringPropertyName)
|
||||
.build();
|
||||
SchemaTypeConfigProto schemaTypeConfigProto =
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.addProperties(emptyStringListProperty)
|
||||
.setSchemaType(SCHEMA_TYPE_1)
|
||||
.build();
|
||||
Map<String, SchemaTypeConfigProto> schemaMap =
|
||||
ImmutableMap.of(PREFIX + SCHEMA_TYPE_1, schemaTypeConfigProto);
|
||||
|
||||
GenericDocument convertedDocument =
|
||||
GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX, schemaMap);
|
||||
|
||||
GenericDocument expectedDocument =
|
||||
new GenericDocument.Builder<GenericDocument.Builder<?>>(
|
||||
"namespace", "uri1", SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMillis(5L)
|
||||
.setPropertyString(emptyStringPropertyName)
|
||||
.build();
|
||||
assertThat(convertedDocument).isEqualTo(expectedDocument);
|
||||
assertThat(expectedDocument.getPropertyStringArray(emptyStringPropertyName)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertDocument_whenNestedDocumentPropertyHasEmptyList() {
|
||||
String emptyStringPropertyName = "emptyStringProperty";
|
||||
String documentPropertyName = "documentProperty";
|
||||
DocumentProto nestedDocumentProto =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri("uri2")
|
||||
.setSchema(SCHEMA_TYPE_2)
|
||||
.setCreationTimestampMs(5L)
|
||||
.setNamespace("namespace")
|
||||
.addProperties(
|
||||
PropertyProto.newBuilder().setName(emptyStringPropertyName).build())
|
||||
.build();
|
||||
DocumentProto documentProto =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri("uri1")
|
||||
.setSchema(SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMs(5L)
|
||||
.setNamespace("namespace")
|
||||
.addProperties(
|
||||
PropertyProto.newBuilder()
|
||||
.addDocumentValues(nestedDocumentProto)
|
||||
.setName(documentPropertyName)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
PropertyConfigProto documentProperty =
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
|
||||
.setDataType(PropertyConfigProto.DataType.Code.DOCUMENT)
|
||||
.setPropertyName(documentPropertyName)
|
||||
.setSchemaType(SCHEMA_TYPE_2)
|
||||
.build();
|
||||
SchemaTypeConfigProto schemaTypeConfigProto =
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.addProperties(documentProperty)
|
||||
.setSchemaType(SCHEMA_TYPE_1)
|
||||
.build();
|
||||
PropertyConfigProto emptyStringListProperty =
|
||||
PropertyConfigProto.newBuilder()
|
||||
.setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
|
||||
.setDataType(PropertyConfigProto.DataType.Code.STRING)
|
||||
.setPropertyName(emptyStringPropertyName)
|
||||
.build();
|
||||
SchemaTypeConfigProto nestedSchemaTypeConfigProto =
|
||||
SchemaTypeConfigProto.newBuilder()
|
||||
.addProperties(emptyStringListProperty)
|
||||
.setSchemaType(SCHEMA_TYPE_2)
|
||||
.build();
|
||||
Map<String, SchemaTypeConfigProto> schemaMap =
|
||||
ImmutableMap.of(
|
||||
PREFIX + SCHEMA_TYPE_1,
|
||||
schemaTypeConfigProto,
|
||||
PREFIX + SCHEMA_TYPE_2,
|
||||
nestedSchemaTypeConfigProto);
|
||||
|
||||
GenericDocument convertedDocument =
|
||||
GenericDocumentToProtoConverter.toGenericDocument(documentProto, PREFIX, schemaMap);
|
||||
|
||||
GenericDocument expectedDocument =
|
||||
new GenericDocument.Builder<GenericDocument.Builder<?>>(
|
||||
"namespace", "uri1", SCHEMA_TYPE_1)
|
||||
.setCreationTimestampMillis(5L)
|
||||
.setPropertyDocument(
|
||||
documentPropertyName,
|
||||
new GenericDocument.Builder<GenericDocument.Builder<?>>(
|
||||
"namespace", "uri2", SCHEMA_TYPE_2)
|
||||
.setCreationTimestampMillis(5L)
|
||||
.setPropertyString(emptyStringPropertyName)
|
||||
.build())
|
||||
.build();
|
||||
assertThat(convertedDocument).isEqualTo(expectedDocument);
|
||||
assertThat(
|
||||
expectedDocument
|
||||
.getPropertyDocument(documentPropertyName)
|
||||
.getPropertyStringArray(emptyStringPropertyName))
|
||||
.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import android.app.appsearch.SearchResult;
|
||||
import android.app.appsearch.SearchResultPage;
|
||||
|
||||
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
|
||||
import com.android.server.appsearch.proto.DocumentProto;
|
||||
import com.android.server.appsearch.proto.PropertyProto;
|
||||
import com.android.server.appsearch.proto.SchemaTypeConfigProto;
|
||||
import com.android.server.appsearch.proto.SearchResultProto;
|
||||
import com.android.server.appsearch.proto.SnippetMatchProto;
|
||||
import com.android.server.appsearch.proto.SnippetProto;
|
||||
@@ -30,20 +32,29 @@ import com.android.server.appsearch.proto.SnippetProto;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class SnippetTest {
|
||||
private static final String SCHEMA_TYPE = "schema1";
|
||||
private static final String PACKAGE_NAME = "packageName";
|
||||
private static final String DATABASE_NAME = "databaseName";
|
||||
private static final String PREFIX = PrefixUtil.createPrefix(PACKAGE_NAME, DATABASE_NAME);
|
||||
private static final SchemaTypeConfigProto SCHEMA_TYPE_CONFIG_PROTO =
|
||||
SchemaTypeConfigProto.newBuilder().setSchemaType(PREFIX + SCHEMA_TYPE).build();
|
||||
private static final Map<String, Map<String, SchemaTypeConfigProto>> SCHEMA_MAP =
|
||||
Collections.singletonMap(
|
||||
PREFIX,
|
||||
Collections.singletonMap(PREFIX + SCHEMA_TYPE, SCHEMA_TYPE_CONFIG_PROTO));
|
||||
|
||||
// TODO(tytytyww): Add tests for Double and Long Snippets.
|
||||
@Test
|
||||
public void testSingleStringSnippet() {
|
||||
|
||||
final String propertyKeyString = "content";
|
||||
final String propertyValueString =
|
||||
"A commonly used fake word is foo.\n"
|
||||
+ " Another nonsense word that’s used a lot\n"
|
||||
+ " is bar.\n";
|
||||
final String uri = "uri1";
|
||||
final String schemaType = "schema1";
|
||||
final String searchWord = "foo";
|
||||
final String exactMatch = "foo";
|
||||
final String window = "is foo";
|
||||
@@ -57,7 +68,7 @@ public class SnippetTest {
|
||||
DocumentProto documentProto =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri(uri)
|
||||
.setSchema(schemaType)
|
||||
.setSchema(SCHEMA_TYPE)
|
||||
.addProperties(property)
|
||||
.build();
|
||||
SnippetProto snippetProto =
|
||||
@@ -86,8 +97,9 @@ public class SnippetTest {
|
||||
SearchResultPage searchResultPage =
|
||||
SearchResultToProtoConverter.toSearchResultPage(
|
||||
searchResultProto,
|
||||
Collections.singletonList("packageName"),
|
||||
Collections.singletonList("databaseName"));
|
||||
Collections.singletonList(PACKAGE_NAME),
|
||||
Collections.singletonList(DATABASE_NAME),
|
||||
SCHEMA_MAP);
|
||||
for (SearchResult result : searchResultPage.getResults()) {
|
||||
SearchResult.MatchInfo match = result.getMatches().get(0);
|
||||
assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
|
||||
@@ -112,7 +124,6 @@ public class SnippetTest {
|
||||
+ " Another nonsense word that’s used a lot\n"
|
||||
+ " is bar.\n";
|
||||
final String uri = "uri1";
|
||||
final String schemaType = "schema1";
|
||||
final String searchWord = "foo";
|
||||
final String exactMatch = "foo";
|
||||
final String window = "is foo";
|
||||
@@ -126,7 +137,7 @@ public class SnippetTest {
|
||||
DocumentProto documentProto =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri(uri)
|
||||
.setSchema(schemaType)
|
||||
.setSchema(SCHEMA_TYPE)
|
||||
.addProperties(property)
|
||||
.build();
|
||||
SearchResultProto.ResultProto resultProto =
|
||||
@@ -137,8 +148,9 @@ public class SnippetTest {
|
||||
SearchResultPage searchResultPage =
|
||||
SearchResultToProtoConverter.toSearchResultPage(
|
||||
searchResultProto,
|
||||
Collections.singletonList("packageName"),
|
||||
Collections.singletonList("databaseName"));
|
||||
Collections.singletonList(PACKAGE_NAME),
|
||||
Collections.singletonList(DATABASE_NAME),
|
||||
SCHEMA_MAP);
|
||||
for (SearchResult result : searchResultPage.getResults()) {
|
||||
assertThat(result.getMatches()).isEmpty();
|
||||
}
|
||||
@@ -162,7 +174,7 @@ public class SnippetTest {
|
||||
DocumentProto documentProto =
|
||||
DocumentProto.newBuilder()
|
||||
.setUri("uri1")
|
||||
.setSchema("schema1")
|
||||
.setSchema(SCHEMA_TYPE)
|
||||
.addProperties(property1)
|
||||
.addProperties(property2)
|
||||
.build();
|
||||
@@ -203,8 +215,9 @@ public class SnippetTest {
|
||||
SearchResultPage searchResultPage =
|
||||
SearchResultToProtoConverter.toSearchResultPage(
|
||||
searchResultProto,
|
||||
Collections.singletonList("packageName"),
|
||||
Collections.singletonList("databaseName"));
|
||||
Collections.singletonList(PACKAGE_NAME),
|
||||
Collections.singletonList(DATABASE_NAME),
|
||||
SCHEMA_MAP);
|
||||
for (SearchResult result : searchResultPage.getResults()) {
|
||||
|
||||
SearchResult.MatchInfo match1 = result.getMatches().get(0);
|
||||
|
||||
Reference in New Issue
Block a user