summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/appsearch/framework/api/current.txt20
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java23
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java5
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java1
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java40
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java2
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java4
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java2
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java80
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java29
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java31
-rw-r--r--apex/appsearch/synced_jetpack_changeid.txt2
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java2
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java157
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java62
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java16
-rw-r--r--core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java94
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java11
19 files changed, 384 insertions, 198 deletions
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index ae9e7ff8de2f..ae32fba443f6 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -100,6 +100,7 @@ package android.app.appsearch {
method public long getCreationTimestampMillis();
method public static int getMaxIndexedProperties();
method @NonNull public String getNamespace();
+ method @Nullable public Object getProperty(@NonNull String);
method public boolean getPropertyBoolean(@NonNull String);
method @Nullable public boolean[] getPropertyBooleanArray(@NonNull String);
method @Nullable public byte[] getPropertyBytes(@NonNull String);
@@ -148,6 +149,12 @@ package android.app.appsearch {
method @NonNull public android.app.appsearch.GetByUriRequest.Builder setNamespace(@NonNull String);
}
+ public class PackageIdentifier {
+ ctor public PackageIdentifier(@NonNull String, @NonNull byte[]);
+ method @NonNull public String getPackageName();
+ method @NonNull public byte[] getSha256Certificate();
+ }
+
public final class PutDocumentsRequest {
method @NonNull public java.util.List<android.app.appsearch.GenericDocument> getDocuments();
}
@@ -233,6 +240,8 @@ package android.app.appsearch {
public final class SetSchemaRequest {
method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
+ method @NonNull public java.util.Set<java.lang.String> getSchemasNotVisibleToSystemUi();
+ method @NonNull public java.util.Map<java.lang.String,java.util.Set<android.app.appsearch.PackageIdentifier>> getSchemasVisibleToPackages();
method public boolean isForceOverride();
}
@@ -242,6 +251,17 @@ package android.app.appsearch {
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
method @NonNull public android.app.appsearch.SetSchemaRequest build();
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(@NonNull String, boolean, @NonNull android.app.appsearch.PackageIdentifier);
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(@NonNull String, boolean);
+ }
+
+}
+
+package android.app.appsearch.exceptions {
+
+ public class AppSearchException extends java.lang.Exception {
+ method public int getResultCode();
+ method @NonNull public <T> android.app.appsearch.AppSearchResult<T> toAppSearchResult();
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index 85207f7ed9d7..11e7fab2b7d9 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -20,7 +20,6 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.util.BundleUtil;
import android.os.Bundle;
import android.util.Log;
@@ -92,9 +91,7 @@ public class GenericDocument {
/** Contains {@link GenericDocument} basic information (uri, schemaType etc). */
@NonNull final Bundle mBundle;
- /**
- * Contains all properties in {@link GenericDocument} to support getting properties via keys.
- */
+ /** Contains all properties in {@link GenericDocument} to support getting properties via keys */
@NonNull private final Bundle mProperties;
@NonNull private final String mUri;
@@ -202,6 +199,24 @@ public class GenericDocument {
}
/**
+ * Retrieves the property value with the given key as {@link Object}.
+ *
+ * @param key The key to look for.
+ * @return The entry with the given key as an object or {@code null} if there is no such key.
+ */
+ @Nullable
+ public Object getProperty(@NonNull String key) {
+ Preconditions.checkNotNull(key);
+ Object property = mProperties.get(key);
+ if (property instanceof ArrayList) {
+ return getPropertyBytesArray(key);
+ } else if (property instanceof Bundle[]) {
+ return getPropertyDocumentArray(key);
+ }
+ return property;
+ }
+
+ /**
* Retrieves a {@link String} value by key.
*
* @param key The key to look for.
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
index 8b20c0903ce1..43be442bd4dc 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java
@@ -23,10 +23,7 @@ import com.android.internal.util.Preconditions;
import java.util.Arrays;
import java.util.Objects;
-/**
- * This class represents a uniquely identifiable package.
- * @hide
- */
+/** This class represents a uniquely identifiable package. */
public class PackageIdentifier {
private final String mPackageName;
private final byte[] mSha256Certificate;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
index 1c360a65a041..b9503eed153c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -18,7 +18,6 @@ package android.app.appsearch;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
import com.android.internal.util.Preconditions;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index 5ffa7c94087c..eb0b7324a117 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -49,31 +49,20 @@ public final class SearchResult {
/** @hide */
public static final String MATCHES_FIELD = "matches";
- @NonNull private final Bundle mBundle;
+ /** @hide */
+ public static final String PACKAGE_NAME_FIELD = "packageName";
- @NonNull private final Bundle mDocumentBundle;
+ @NonNull private final Bundle mBundle;
/** Cache of the inflated document. Comes from inflating mDocumentBundle at first use. */
@Nullable private GenericDocument mDocument;
- /**
- * Contains a list of MatchInfo bundles that matched the request.
- *
- * <p>Only populated when requested in both {@link SearchSpec.Builder#setSnippetCount} and
- * {@link SearchSpec.Builder#setSnippetCountPerProperty}.
- *
- * @see #getMatches()
- */
- @NonNull private final List<Bundle> mMatchBundles;
-
/** Cache of the inflated matches. Comes from inflating mMatchBundles at first use. */
@Nullable private List<MatchInfo> mMatches;
/** @hide */
public SearchResult(@NonNull Bundle bundle) {
mBundle = Preconditions.checkNotNull(bundle);
- mDocumentBundle = Preconditions.checkNotNull(bundle.getBundle(DOCUMENT_FIELD));
- mMatchBundles = Preconditions.checkNotNull(bundle.getParcelableArrayList(MATCHES_FIELD));
}
/** @hide */
@@ -90,7 +79,9 @@ public final class SearchResult {
@NonNull
public GenericDocument getDocument() {
if (mDocument == null) {
- mDocument = new GenericDocument(mDocumentBundle);
+ mDocument =
+ new GenericDocument(
+ Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
}
return mDocument;
}
@@ -106,9 +97,11 @@ public final class SearchResult {
@NonNull
public List<MatchInfo> getMatches() {
if (mMatches == null) {
- mMatches = new ArrayList<>(mMatchBundles.size());
- for (int i = 0; i < mMatchBundles.size(); i++) {
- MatchInfo matchInfo = new MatchInfo(getDocument(), mMatchBundles.get(i));
+ List<Bundle> matchBundles =
+ Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
+ mMatches = new ArrayList<>(matchBundles.size());
+ for (int i = 0; i < matchBundles.size(); i++) {
+ MatchInfo matchInfo = new MatchInfo(getDocument(), matchBundles.get(i));
mMatches.add(matchInfo);
}
}
@@ -116,6 +109,17 @@ public final class SearchResult {
}
/**
+ * Contains the package name that stored the {@link GenericDocument}.
+ *
+ * @return Package name that stored the document
+ * @hide
+ */
+ @NonNull
+ public String getPackageName() {
+ return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
+ }
+
+ /**
* This class represents a match objects for any Snippets that might be present in {@link
* SearchResults} from query. Using this class user can get the full text, exact matches and
* Snippets of document content for a given match.
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index 400b6303d12e..c3f0d8ab53e3 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -19,8 +19,6 @@ package android.app.appsearch;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.exceptions.IllegalSearchSpecException;
import android.os.Bundle;
import android.util.ArrayMap;
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index ad3ee0587f61..e9c4cb4e9e34 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -59,7 +59,6 @@ public final class SetSchemaRequest {
/**
* Returns the set of schema types that have opted out of being visible on system UI surfaces.
- * @hide
*/
@NonNull
public Set<String> getSchemasNotVisibleToSystemUi() {
@@ -72,7 +71,6 @@ public final class SetSchemaRequest {
* certificate.
*
* <p>This method is inefficient to call repeatedly.
- * @hide
*/
@NonNull
public Map<String, Set<PackageIdentifier>> getSchemasVisibleToPackages() {
@@ -141,7 +139,6 @@ public final class SetSchemaRequest {
*
* @param schemaType The schema type to set visibility on.
* @param visible Whether the {@code schemaType} will be visible or not.
- * @hide
*/
// Merged list available from getSchemasNotVisibleToSystemUi
@SuppressLint("MissingGetterMatchingBuilder")
@@ -165,7 +162,6 @@ public final class SetSchemaRequest {
* @param schemaType The schema type to set visibility on.
* @param visible Whether the {@code schemaType} will be visible or not.
* @param packageIdentifier Represents the package that will be granted visibility.
- * @hide
*/
// Merged list available from getSchemasVisibleToPackages
@SuppressLint("MissingGetterMatchingBuilder")
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
index 704f180bffc4..b1a33a478a47 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
@@ -25,8 +25,6 @@ import android.app.appsearch.AppSearchResult;
*
* <p>These exceptions can be converted into a failed {@link AppSearchResult} for propagating to the
* client.
- *
- * @hide
*/
public class AppSearchException extends Exception {
private final @AppSearchResult.ResultCode int mResultCode;
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 47a81eb37c7d..a2126b19d31e 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -37,6 +37,7 @@ import com.android.server.appsearch.external.localstorage.converter.SearchResult
import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
import com.google.android.icing.IcingSearchEngine;
+import com.google.android.icing.proto.DeleteByQueryResultProto;
import com.google.android.icing.proto.DeleteResultProto;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.GetAllNamespacesResultProto;
@@ -609,7 +610,7 @@ public final class AppSearchImpl {
SearchSpecProto searchSpecProto = SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
SearchSpecProto.Builder searchSpecBuilder =
searchSpecProto.toBuilder().setQuery(queryExpression);
- DeleteResultProto deleteResultProto;
+ DeleteByQueryResultProto deleteResultProto;
mReadWriteLock.writeLock().lock();
try {
// Only rewrite SearchSpec for non empty prefixes.
@@ -797,11 +798,27 @@ public final class AppSearchImpl {
* 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 void removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
+ 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()));
@@ -816,12 +833,22 @@ public final class AppSearchImpl {
for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
DocumentProto.Builder derivedDocumentBuilder =
propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- removePrefixesFromDocument(derivedDocumentBuilder);
+ 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;
}
/**
@@ -929,6 +956,25 @@ public final class AppSearchImpl {
return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_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 name: " + prefix);
+ return "";
+ }
+ return prefix.substring(0, delimiterIndex);
+ }
+
@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
@@ -949,7 +995,7 @@ public final class AppSearchImpl {
if (databaseDelimiterIndex == -1) {
throw new AppSearchException(
AppSearchResult.RESULT_UNKNOWN_ERROR,
- "The databaseName prefixed value doesn't contains a valid database name.");
+ "The databaseName prefixed value doesn't contain a valid database name.");
}
// Add 1 to include the char size of the DATABASE_DELIMITER
@@ -1034,20 +1080,24 @@ public final class AppSearchImpl {
}
/** Remove the rewritten schema types from any result documents. */
- private static SearchResultPage rewriteSearchResultProto(
- @NonNull SearchResultProto searchResultProto) throws AppSearchException {
+ @NonNull
+ @VisibleForTesting
+ static SearchResultPage rewriteSearchResultProto(@NonNull SearchResultProto searchResultProto)
+ throws AppSearchException {
+ // Parallel array of package names for each document search result.
+ List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());
+
SearchResultProto.Builder resultsBuilder = searchResultProto.toBuilder();
for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
- if (searchResultProto.getResults(i).hasDocument()) {
- SearchResultProto.ResultProto.Builder resultBuilder =
- searchResultProto.getResults(i).toBuilder();
- DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
- removePrefixesFromDocument(documentBuilder);
- resultBuilder.setDocument(documentBuilder);
- resultsBuilder.setResults(i, resultBuilder);
- }
+ SearchResultProto.ResultProto.Builder resultBuilder =
+ searchResultProto.getResults(i).toBuilder();
+ DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
+ String prefix = removePrefixesFromDocument(documentBuilder);
+ packageNames.add(getPackageName(prefix));
+ resultBuilder.setDocument(documentBuilder);
+ resultsBuilder.setResults(i, resultBuilder);
}
- return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder);
+ return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder, packageNames);
}
@GuardedBy("mReadWriteLock")
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index 5474cd04287c..a2386eccc256 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -54,40 +54,43 @@ public final class GenericDocumentToProtoConverter {
for (int i = 0; i < keys.size(); i++) {
String name = keys.get(i);
PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
- String[] stringValues = document.getPropertyStringArray(name);
- long[] longValues = document.getPropertyLongArray(name);
- double[] doubleValues = document.getPropertyDoubleArray(name);
- boolean[] booleanValues = document.getPropertyBooleanArray(name);
- byte[][] bytesValues = document.getPropertyBytesArray(name);
- GenericDocument[] documentValues = document.getPropertyDocumentArray(name);
- if (stringValues != null) {
+ Object property = document.getProperty(name);
+ if (property instanceof String[]) {
+ String[] stringValues = (String[]) property;
for (int j = 0; j < stringValues.length; j++) {
propertyProto.addStringValues(stringValues[j]);
}
- } else if (longValues != null) {
+ } else if (property instanceof long[]) {
+ long[] longValues = (long[]) property;
for (int j = 0; j < longValues.length; j++) {
propertyProto.addInt64Values(longValues[j]);
}
- } else if (doubleValues != null) {
+ } else if (property instanceof double[]) {
+ double[] doubleValues = (double[]) property;
for (int j = 0; j < doubleValues.length; j++) {
propertyProto.addDoubleValues(doubleValues[j]);
}
- } else if (booleanValues != null) {
+ } else if (property instanceof boolean[]) {
+ boolean[] booleanValues = (boolean[]) property;
for (int j = 0; j < booleanValues.length; j++) {
propertyProto.addBooleanValues(booleanValues[j]);
}
- } else if (bytesValues != null) {
+ } else if (property instanceof byte[][]) {
+ byte[][] bytesValues = (byte[][]) property;
for (int j = 0; j < bytesValues.length; j++) {
propertyProto.addBytesValues(ByteString.copyFrom(bytesValues[j]));
}
- } else if (documentValues != null) {
+ } else if (property instanceof GenericDocument[]) {
+ GenericDocument[] documentValues = (GenericDocument[]) property;
for (int j = 0; j < documentValues.length; j++) {
DocumentProto proto = toDocumentProto(documentValues[j]);
propertyProto.addDocumentValues(proto);
}
} else {
throw new IllegalStateException(
- "Property \"" + name + "\" has unsupported value type");
+ String.format(
+ "Property \"%s\" has unsupported value type %s",
+ name, property.getClass().toString()));
}
mProtoBuilder.addProperties(propertyProto);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index 4d107a970abd..ccd567d1c945 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -22,12 +22,15 @@ import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultPage;
import android.os.Bundle;
+import com.android.internal.util.Preconditions;
+
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchResultProtoOrBuilder;
import com.google.android.icing.proto.SnippetMatchProto;
import com.google.android.icing.proto.SnippetProto;
import java.util.ArrayList;
+import java.util.List;
/**
* Translates a {@link SearchResultProto} into {@link SearchResult}s.
@@ -37,27 +40,45 @@ import java.util.ArrayList;
public class SearchResultToProtoConverter {
private SearchResultToProtoConverter() {}
- /** Translate a {@link SearchResultProto} into {@link SearchResultPage}. */
+ /**
+ * Translate a {@link SearchResultProto} into {@link SearchResultPage}.
+ *
+ * @param proto The {@link SearchResultProto} containing results.
+ * @param packageNames A parallel array of package names. The package name at index 'i' of this
+ * list should be the package that indexed the document at index 'i' of proto.getResults(i).
+ * @return {@link SearchResultPage} of results.
+ */
@NonNull
- public static SearchResultPage toSearchResultPage(@NonNull SearchResultProtoOrBuilder proto) {
+ public static SearchResultPage toSearchResultPage(
+ @NonNull SearchResultProtoOrBuilder proto, @NonNull List<String> packageNames) {
+ Preconditions.checkArgument(
+ proto.getResultsCount() == packageNames.size(),
+ "Size of " + "results does not match the number of package names.");
Bundle bundle = new Bundle();
bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
for (int i = 0; i < proto.getResultsCount(); i++) {
- resultBundles.add(toSearchResultBundle(proto.getResults(i)));
+ resultBundles.add(toSearchResultBundle(proto.getResults(i), packageNames.get(i)));
}
bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
return new SearchResultPage(bundle);
}
- /** Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}. */
+ /**
+ * Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}.
+ *
+ * @param proto The proto to be converted.
+ * @param packageName The package name associated with the document in {@code proto}.
+ * @return A {@link SearchResult} bundle.
+ */
@NonNull
private static Bundle toSearchResultBundle(
- @NonNull SearchResultProto.ResultProtoOrBuilder proto) {
+ @NonNull SearchResultProto.ResultProtoOrBuilder proto, @NonNull String packageName) {
Bundle bundle = new Bundle();
GenericDocument document =
GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle());
+ bundle.putString(SearchResult.PACKAGE_NAME_FIELD, packageName);
ArrayList<Bundle> matchList = new ArrayList<>();
if (proto.hasSnippet()) {
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 2b1ec08e1d8e..73f64dc500ae 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I596ad1269b4d3a4f26db67f5d970aeaa3bf94a9d
+I8b7425b3f87153547d1c8f5b560be5a54c9be97e
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
index 9e22bf6ddbbf..6859747286a8 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
@@ -46,7 +46,7 @@ public class GlobalSearchSessionShimImpl implements GlobalSearchSessionShim {
private final ExecutorService mExecutor;
@NonNull
- public static ListenableFuture<GlobalSearchSessionShimImpl> createGlobalSearchSession() {
+ public static ListenableFuture<GlobalSearchSessionShim> createGlobalSearchSession() {
Context context = ApplicationProvider.getApplicationContext();
AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
SettableFuture<AppSearchResult<GlobalSearchSession>> future = SettableFuture.create();
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index 8383df4dd0cd..e439c5ab3947 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.app.appsearch;
import android.annotation.NonNull;
@@ -26,7 +27,7 @@ import java.util.Set;
* Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
* placed and queried.
*
- * All implementations of this interface must be thread safe.
+ * <p>All implementations of this interface must be thread safe.
*/
public interface AppSearchSessionShim {
@@ -37,41 +38,42 @@ public interface AppSearchSessionShim {
* to {@link #setSchema}, if any, to determine how to treat existing documents. The following
* types of schema modifications are always safe and are made without deleting any existing
* documents:
+ *
* <ul>
- * <li>Addition of new types
- * <li>Addition of new
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
- * type
- * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
+ * <li>Addition of new types
+ * <li>Addition of new {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
+ * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
+ * type
+ * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an {@link
+ * AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
+ * AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
* </ul>
*
* <p>The following types of schema changes are not backwards-compatible:
+ *
* <ul>
- * <li>Removal of an existing type
- * <li>Removal of a property from a type
- * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
- * <li>For properties of {@code Document} type, changing the schema type of
- * {@code Document}s of that property
- * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
- * <li>Adding a
- * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
+ * <li>Removal of an existing type
+ * <li>Removal of a property from a type
+ * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
+ * <li>For properties of {@code Document} type, changing the schema type of {@code Document}s
+ * of that property
+ * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an {@link
+ * AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a {@link
+ * AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
+ * <li>Adding a {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
* </ul>
+ *
* <p>Supplying a schema with such changes will, by default, result in this call completing its
- * future with an {@link androidx.appsearch.exceptions.AppSearchException} with a code of
+ * future with an {@link android.app.appsearch.exceptions.AppSearchException} with a code of
* {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility.
* In this case the previously set schema will remain active.
*
* <p>If you need to make non-backwards-compatible changes as described above, you can set the
* {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In this case,
- * instead of completing its future with an
- * {@link androidx.appsearch.exceptions.AppSearchException} with the
- * {@link AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
- * compatible with the new schema will be deleted and the incompatible schema will be applied.
+ * instead of completing its future with an {@link
+ * android.app.appsearch.exceptions.AppSearchException} with the {@link
+ * AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not compatible
+ * with the new schema will be deleted and the incompatible schema will be applied.
*
* <p>It is a no-op to set the same schema as has been previously set; this is handled
* efficiently.
@@ -79,8 +81,8 @@ public interface AppSearchSessionShim {
* <p>By default, documents are visible on platform surfaces. To opt out, call {@code
* SetSchemaRequest.Builder#setPlatformSurfaceable} with {@code surfaceable} as false. Any
* visibility settings apply only to the schemas that are included in the {@code request}.
- * Visibility settings for a schema type do not apply or persist across
- * {@link SetSchemaRequest}s.
+ * Visibility settings for a schema type do not apply or persist across {@link
+ * SetSchemaRequest}s.
*
* @param request The schema update request.
* @return The pending result of performing this operation.
@@ -107,10 +109,9 @@ public interface AppSearchSessionShim {
* schema type previously registered via the {@link #setSchema} method.
*
* @param request {@link PutDocumentsRequest} containing documents to be indexed
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the URIs of the input documents. The values are
- * {@code null} if they were successfully indexed, or a failed {@link AppSearchResult}
- * otherwise.
+ * @return The pending result of performing this operation. The keys of the returned {@link
+ * AppSearchBatchResult} are the URIs of the input documents. The values are {@code null} if
+ * they were successfully indexed, or a failed {@link AppSearchResult} otherwise.
*/
@NonNull
ListenableFuture<AppSearchBatchResult<String, Void>> putDocuments(
@@ -120,11 +121,11 @@ public interface AppSearchSessionShim {
* Retrieves {@link GenericDocument}s by URI.
*
* @param request {@link GetByUriRequest} containing URIs to be retrieved.
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the input URIs. The values are the returned
- * {@link GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise.
- * URIs that are not found will return a failed {@link AppSearchResult} with a result code
- * of {@link AppSearchResult#RESULT_NOT_FOUND}.
+ * @return The pending result of performing this operation. The keys of the returned {@link
+ * AppSearchBatchResult} are the input URIs. The values are the returned {@link
+ * GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise. URIs that
+ * are not found will return a failed {@link AppSearchResult} with a result code of {@link
+ * AppSearchResult#RESULT_NOT_FOUND}.
*/
@NonNull
ListenableFuture<AppSearchBatchResult<String, GenericDocument>> getByUri(
@@ -134,42 +135,39 @@ public interface AppSearchSessionShim {
* Searches a document based on a given query string.
*
* <p>Currently we support following features in the raw query format:
+ *
* <ul>
- * <li>AND
- * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
- * ‘cat’”).
- * Example: hello world matches documents that have both ‘hello’ and ‘world’
- * <li>OR
- * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
- * ‘cat’”).
- * Example: dog OR puppy
- * <li>Exclusion
- * <p>Exclude a term (e.g. “match documents that do
- * not have the term ‘dog’”).
- * Example: -dog excludes the term ‘dog’
- * <li>Grouping terms
- * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
- * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
- * Example: (dog puppy) (cat kitten) two one group containing two terms.
- * <li>Property restricts
- * <p> Specifies which properties of a document to specifically match terms in (e.g.
- * “match documents where the ‘subject’ property contains ‘important’”).
- * Example: subject:important matches documents with the term ‘important’ in the
- * ‘subject’ property
- * <li>Schema type restricts
- * <p>This is similar to property restricts, but allows for restricts on top-level document
- * fields, such as schema_type. Clients should be able to limit their query to documents of
- * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
- * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
- * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
- * ‘Video’ schema type.
+ * <li>AND
+ * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and ‘cat’”).
+ * Example: hello world matches documents that have both ‘hello’ and ‘world’
+ * <li>OR
+ * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or ‘cat’”). Example:
+ * dog OR puppy
+ * <li>Exclusion
+ * <p>Exclude a term (e.g. “match documents that do not have the term ‘dog’”). Example:
+ * -dog excludes the term ‘dog’
+ * <li>Grouping terms
+ * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+ * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+ * Example: (dog puppy) (cat kitten) two one group containing two terms.
+ * <li>Property restricts
+ * <p>Specifies which properties of a document to specifically match terms in (e.g. “match
+ * documents where the ‘subject’ property contains ‘important’”). Example:
+ * subject:important matches documents with the term ‘important’ in the ‘subject’ property
+ * <li>Schema type restricts
+ * <p>This is similar to property restricts, but allows for restricts on top-level
+ * document fields, such as schema_type. Clients should be able to limit their query to
+ * documents of a certain schema_type (e.g. “match documents that are of the ‘Email’
+ * schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will
+ * match documents that contain the query term ‘dog’ and are of either the ‘Email’ schema
+ * type or the ‘Video’ schema type.
* </ul>
*
- * <p> This method is lightweight. The heavy work will be done in
- * {@link SearchResults#getNextPage()}.
+ * <p>This method is lightweight. The heavy work will be done in {@link
+ * SearchResultsShim#getNextPage()}.
*
* @param queryExpression Query String to search.
- * @param searchSpec Spec for setting filters, raw query etc.
+ * @param searchSpec Spec for setting filters, raw query etc.
* @return The search result of performing this operation.
*/
@NonNull
@@ -179,11 +177,10 @@ public interface AppSearchSessionShim {
* Removes {@link GenericDocument}s from the index by URI.
*
* @param request Request containing URIs to be removed.
- * @return The pending result of performing this operation. The keys of the returned
- * {@link AppSearchBatchResult} are the input URIs. The values are {@code null} on success,
- * or a failed {@link AppSearchResult} otherwise. URIs that are not found will return a
- * failed {@link AppSearchResult} with a result code of
- * {@link AppSearchResult#RESULT_NOT_FOUND}.
+ * @return The pending result of performing this operation. The keys of the returned {@link
+ * AppSearchBatchResult} are the input URIs. The values are {@code null} on success, or a
+ * failed {@link AppSearchResult} otherwise. URIs that are not found will return a failed
+ * {@link AppSearchResult} with a result code of {@link AppSearchResult#RESULT_NOT_FOUND}.
*/
@NonNull
ListenableFuture<AppSearchBatchResult<String, Void>> removeByUri(
@@ -191,18 +188,18 @@ public interface AppSearchSessionShim {
/**
* Removes {@link GenericDocument}s from the index by Query. Documents will be removed if they
- * match the {@code queryExpression} in given namespaces and schemaTypes which is set via
- * {@link SearchSpec.Builder#addNamespace} and {@link SearchSpec.Builder#addSchemaType}.
+ * match the {@code queryExpression} in given namespaces and schemaTypes which is set via {@link
+ * SearchSpec.Builder#addNamespace} and {@link SearchSpec.Builder#addSchemaType}.
*
- * <p> An empty {@code queryExpression} matches all documents.
+ * <p>An empty {@code queryExpression} matches all documents.
*
- * <p> An empty set of namespaces or schemaTypes matches all namespaces or schemaTypes in
- * the current database.
+ * <p>An empty set of namespaces or schemaTypes matches all namespaces or schemaTypes in the
+ * current database.
*
* @param queryExpression Query String to search.
- * @param searchSpec Spec containing schemaTypes, namespaces and query expression
- * indicates how document will be removed. All specific about how to
- * scoring, ordering, snippeting and resulting will be ignored.
+ * @param searchSpec Spec containing schemaTypes, namespaces and query expression indicates how
+ * document will be removed. All specific about how to scoring, ordering, snippeting and
+ * resulting will be ignored.
* @return The pending result of performing this operation.
*/
@NonNull
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
index 33dc3795325b..2d09247dfbc9 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.app.appsearch;
import android.annotation.NonNull;
@@ -27,42 +28,39 @@ public interface GlobalSearchSessionShim {
* Searches across all documents in the storage based on a given query string.
*
* <p>Currently we support following features in the raw query format:
+ *
* <ul>
- * <li>AND
- * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
- * ‘cat’”).
- * Example: hello world matches documents that have both ‘hello’ and ‘world’
- * <li>OR
- * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
- * ‘cat’”).
- * Example: dog OR puppy
- * <li>Exclusion
- * <p>Exclude a term (e.g. “match documents that do
- * not have the term ‘dog’”).
- * Example: -dog excludes the term ‘dog’
- * <li>Grouping terms
- * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
- * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
- * Example: (dog puppy) (cat kitten) two one group containing two terms.
- * <li>Property restricts
- * <p> Specifies which properties of a document to specifically match terms in (e.g.
- * “match documents where the ‘subject’ property contains ‘important’”).
- * Example: subject:important matches documents with the term ‘important’ in the
- * ‘subject’ property
- * <li>Schema type restricts
- * <p>This is similar to property restricts, but allows for restricts on top-level document
- * fields, such as schema_type. Clients should be able to limit their query to documents of
- * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
- * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
- * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
- * ‘Video’ schema type.
+ * <li>AND
+ * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and ‘cat’”).
+ * Example: hello world matches documents that have both ‘hello’ and ‘world’
+ * <li>OR
+ * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or ‘cat’”). Example:
+ * dog OR puppy
+ * <li>Exclusion
+ * <p>Exclude a term (e.g. “match documents that do not have the term ‘dog’”). Example:
+ * -dog excludes the term ‘dog’
+ * <li>Grouping terms
+ * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+ * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+ * Example: (dog puppy) (cat kitten) two one group containing two terms.
+ * <li>Property restricts
+ * <p>Specifies which properties of a document to specifically match terms in (e.g. “match
+ * documents where the ‘subject’ property contains ‘important’”). Example:
+ * subject:important matches documents with the term ‘important’ in the ‘subject’ property
+ * <li>Schema type restricts
+ * <p>This is similar to property restricts, but allows for restricts on top-level
+ * document fields, such as schema_type. Clients should be able to limit their query to
+ * documents of a certain schema_type (e.g. “match documents that are of the ‘Email’
+ * schema_type”). Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will
+ * match documents that contain the query term ‘dog’ and are of either the ‘Email’ schema
+ * type or the ‘Video’ schema type.
* </ul>
*
- * <p> This method is lightweight. The heavy work will be done in
- * {@link SearchResults#getNextPage}.
+ * <p>This method is lightweight. The heavy work will be done in {@link
+ * SearchResultsShim#getNextPage()}.
*
* @param queryExpression Query String to search.
- * @param searchSpec Spec for setting filters, raw query etc.
+ * @param searchSpec Spec for setting filters, raw query etc.
* @return The search result of performing this operation.
*/
@NonNull
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
index f387a1740386..328c65ca2727 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.app.appsearch;
import android.annotation.NonNull;
@@ -23,10 +24,10 @@ import java.io.Closeable;
import java.util.List;
/**
- * SearchResults are a returned object from a query API.
+ * SearchResultsShim are a returned object from a query API.
*
- * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets
- * based on request.
+ * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets based
+ * on request.
*
* <p>Should close this object after finish fetching results.
*
@@ -36,11 +37,10 @@ public interface SearchResultsShim extends Closeable {
/**
* Gets a whole page of {@link SearchResult}s.
*
- * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an
- * empty list.
+ * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an empty
+ * list.
*
- * <p>The page size is set by
- * {@link android.app.appsearch.SearchSpec.Builder#setResultCountPerPage}.
+ * <p>The page size is set by {@link SearchSpec.Builder#setResultCountPerPage}.
*
* @return The pending result of performing this operation.
*/
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
index 133efce58b70..aab922972c54 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
@@ -16,6 +16,7 @@
package android.app.appsearch;
+
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.expectThrows;
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index f29b0594db8f..c6fde87f5953 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -22,10 +22,12 @@ import static org.testng.Assert.expectThrows;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
+import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.exceptions.AppSearchException;
+import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
import com.android.server.appsearch.proto.DocumentProto;
import com.android.server.appsearch.proto.GetOptimizeInfoResultProto;
@@ -33,6 +35,7 @@ import com.android.server.appsearch.proto.PropertyConfigProto;
import com.android.server.appsearch.proto.PropertyProto;
import com.android.server.appsearch.proto.SchemaProto;
import com.android.server.appsearch.proto.SchemaTypeConfigProto;
+import com.android.server.appsearch.proto.SearchResultProto;
import com.android.server.appsearch.proto.SearchSpecProto;
import com.android.server.appsearch.proto.StringIndexingConfig;
import com.android.server.appsearch.proto.TermMatchType;
@@ -316,14 +319,14 @@ public class AppSearchImplTest {
DocumentProto insideDocument =
DocumentProto.newBuilder()
.setUri("inside-uri")
- .setSchema("package$databaseName1/type")
- .setNamespace("package$databaseName2/namespace")
+ .setSchema("package$databaseName/type")
+ .setNamespace("package$databaseName/namespace")
.build();
DocumentProto documentProto =
DocumentProto.newBuilder()
.setUri("uri")
- .setSchema("package$databaseName2/type")
- .setNamespace("package$databaseName3/namespace")
+ .setSchema("package$databaseName/type")
+ .setNamespace("package$databaseName/namespace")
.addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
.build();
@@ -345,11 +348,56 @@ public class AppSearchImplTest {
.build();
DocumentProto.Builder actualDocument = documentProto.toBuilder();
- mAppSearchImpl.removePrefixesFromDocument(actualDocument);
+ assertThat(mAppSearchImpl.removePrefixesFromDocument(actualDocument))
+ .isEqualTo("package$databaseName/");
assertThat(actualDocument.build()).isEqualTo(expectedDocumentProto);
}
@Test
+ public void testRemoveDatabasesFromDocumentThrowsException() throws Exception {
+ // Set two different database names in the document, which should never happen
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri")
+ .setSchema("prefix1/type")
+ .setNamespace("prefix2/namespace")
+ .build();
+
+ DocumentProto.Builder actualDocument = documentProto.toBuilder();
+ AppSearchException e =
+ expectThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
+ }
+
+ @Test
+ public void testNestedRemoveDatabasesFromDocumentThrowsException() throws Exception {
+ // Set two different database names in the outer and inner document, which should never
+ // happen.
+ DocumentProto insideDocument =
+ DocumentProto.newBuilder()
+ .setUri("inside-uri")
+ .setSchema("prefix1/type")
+ .setNamespace("prefix1/namespace")
+ .build();
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri("uri")
+ .setSchema("prefix2/type")
+ .setNamespace("prefix2/namespace")
+ .addProperties(PropertyProto.newBuilder().addDocumentValues(insideDocument))
+ .build();
+
+ DocumentProto.Builder actualDocument = documentProto.toBuilder();
+ AppSearchException e =
+ expectThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.removePrefixesFromDocument(actualDocument));
+ assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
+ }
+
+ @Test
public void testOptimize() throws Exception {
// Insert schema
List<AppSearchSchema> schemas =
@@ -865,4 +913,40 @@ public class AppSearchImplTest {
AppSearchImpl.createPrefix("package", "database1"),
AppSearchImpl.createPrefix("package", "database2"));
}
+
+ @Test
+ public void testRewriteSearchResultProto() throws Exception {
+ final String database =
+ "com.package.foo"
+ + AppSearchImpl.PACKAGE_DELIMITER
+ + "databaseName"
+ + AppSearchImpl.DATABASE_DELIMITER;
+ final String uri = "uri";
+ final String namespace = database + "namespace";
+ final String schemaType = database + "schema";
+
+ // Building the SearchResult received from query.
+ DocumentProto documentProto =
+ DocumentProto.newBuilder()
+ .setUri(uri)
+ .setNamespace(namespace)
+ .setSchema(schemaType)
+ .build();
+ SearchResultProto.ResultProto resultProto =
+ SearchResultProto.ResultProto.newBuilder().setDocument(documentProto).build();
+ SearchResultProto searchResultProto =
+ SearchResultProto.newBuilder().addResults(resultProto).build();
+
+ DocumentProto.Builder strippedDocumentProto = documentProto.toBuilder();
+ AppSearchImpl.removePrefixesFromDocument(strippedDocumentProto);
+ SearchResultPage searchResultPage =
+ AppSearchImpl.rewriteSearchResultProto(searchResultProto);
+ for (SearchResult result : searchResultPage.getResults()) {
+ assertThat(result.getPackageName()).isEqualTo("com.package.foo");
+ assertThat(result.getDocument())
+ .isEqualTo(
+ GenericDocumentToProtoConverter.toGenericDocument(
+ strippedDocumentProto.build()));
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index 7c68c6be4883..a3f0f6bf280e 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -29,6 +29,8 @@ import com.android.server.appsearch.proto.SnippetProto;
import org.junit.Test;
+import java.util.Collections;
+
public class SnippetTest {
// TODO(tytytyww): Add tests for Double and Long Snippets.
@@ -83,7 +85,8 @@ public class SnippetTest {
// Making ResultReader and getting Snippet values.
SearchResultPage searchResultPage =
- SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
+ SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto, Collections.singletonList("packageName"));
for (SearchResult result : searchResultPage.getResults()) {
SearchResult.MatchInfo match = result.getMatches().get(0);
assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
@@ -131,7 +134,8 @@ public class SnippetTest {
SearchResultProto.newBuilder().addResults(resultProto).build();
SearchResultPage searchResultPage =
- SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
+ SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto, Collections.singletonList("packageName"));
for (SearchResult result : searchResultPage.getResults()) {
assertThat(result.getMatches()).isEmpty();
}
@@ -196,7 +200,8 @@ public class SnippetTest {
// Making ResultReader and getting Snippet values.
SearchResultPage searchResultPage =
- SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
+ SearchResultToProtoConverter.toSearchResultPage(
+ searchResultProto, Collections.singletonList("packageName"));
for (SearchResult result : searchResultPage.getResults()) {
SearchResult.MatchInfo match1 = result.getMatches().get(0);