From 4306d3f8e7d9acefea9a42f9eb9e5e71a8440fdd Mon Sep 17 00:00:00 2001 From: Alexander Dorokhine Date: Mon, 28 Dec 2020 16:36:50 -0800 Subject: [PATCH] Update framework from Jetpack Included changes: * 8b9027a: Unhide visibility APIs on SetSchemaRequest. * 9079d15: Support collections of subclasses in SetSchemaRequest builder * 3a36aa7: Snapshot global query results in tests. * afbdc54: Fix errors cause by AppSearchImpl.reset. * 2463600: Place CTS tests and test utils into the right places. * 92cd45a: Remove AppSearchResult from methods returning a single value. Bug: 169883602 Bug: 171914169 Bug: 175430168 Bug: 170997047 Bug: 162450968 Test: AppSearchSessionTest Change-Id: I01101e7928e0a0526412f5905ff5d6afa645042b --- .../app/appsearch/AppSearchManager.java | 2 +- .../app/appsearch/AppSearchSession.java | 2 +- .../app/appsearch/PackageIdentifier.java | 31 ++- .../app/appsearch/SetSchemaRequest.java | 59 +++-- .../external/localstorage/AppSearchImpl.java | 17 +- .../localstorage/VisibilityStore.java | 8 +- apex/appsearch/synced_jetpack_changeid.txt | 2 +- ...him.java => AppSearchSessionShimImpl.java} | 56 +++-- ....java => GlobalSearchSessionShimImpl.java} | 23 +- ...tsShim.java => SearchResultsShimImpl.java} | 14 +- .../external/AppSearchSessionShim.java | 211 ++++++++++++++++++ .../testing/external/AppSearchTestUtils.java | 49 +--- .../external/GlobalSearchSessionShim.java | 70 ++++++ .../testing/external/SearchResultsShim.java | 52 +++++ .../external/app/SetSchemaRequestTest.java | 49 ++-- .../localstorage/AppSearchImplTest.java | 2 + 16 files changed, 496 insertions(+), 151 deletions(-) rename apex/appsearch/testing/java/com/android/server/appsearch/testing/{AppSearchSessionShim.java => AppSearchSessionShimImpl.java} (74%) rename apex/appsearch/testing/java/com/android/server/appsearch/testing/{GlobalSearchSessionShim.java => GlobalSearchSessionShimImpl.java} (76%) rename apex/appsearch/testing/java/com/android/server/appsearch/testing/{SearchResultsShim.java => SearchResultsShimImpl.java} (73%) create mode 100644 apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java create mode 100644 apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java create mode 100644 apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index c82119d14670..68a305116c16 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -229,7 +229,7 @@ public class AppSearchManager { mService.setSchema( DEFAULT_DATABASE_NAME, schemaBundles, - new ArrayList<>(request.getSchemasNotPlatformSurfaceable()), + new ArrayList<>(request.getSchemasNotVisibleToSystemUi()), request.isForceOverride(), new IAppSearchResultCallback.Stub() { public void onResult(AppSearchResult result) { diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java index 3e813eab6f04..60caa44f2ba3 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java @@ -152,7 +152,7 @@ public final class AppSearchSession { mService.setSchema( mDatabaseName, schemaBundles, - new ArrayList<>(request.getSchemasNotPlatformSurfaceable()), + new ArrayList<>(request.getSchemasNotVisibleToSystemUi()), request.isForceOverride(), new IAppSearchResultCallback.Stub() { public void onResult(AppSearchResult result) { 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 b567dee6abd8..8b20c0903ce1 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/PackageIdentifier.java @@ -18,27 +18,38 @@ package android.app.appsearch; import android.annotation.NonNull; +import com.android.internal.util.Preconditions; + import java.util.Arrays; import java.util.Objects; /** * This class represents a uniquely identifiable package. - * * @hide */ public class PackageIdentifier { - public final String packageName; - public final byte[] certificate; + private final String mPackageName; + private final byte[] mSha256Certificate; /** * Creates a unique identifier for a package. * * @param packageName Name of the package. - * @param certificate SHA256 certificate digest of the package. + * @param sha256Certificate SHA256 certificate digest of the package. */ - public PackageIdentifier(@NonNull String packageName, @NonNull byte[] certificate) { - this.packageName = packageName; - this.certificate = certificate; + public PackageIdentifier(@NonNull String packageName, @NonNull byte[] sha256Certificate) { + mPackageName = Preconditions.checkNotNull(packageName); + mSha256Certificate = Preconditions.checkNotNull(sha256Certificate); + } + + @NonNull + public String getPackageName() { + return mPackageName; + } + + @NonNull + public byte[] getSha256Certificate() { + return mSha256Certificate; } @Override @@ -50,12 +61,12 @@ public class PackageIdentifier { return false; } final PackageIdentifier other = (PackageIdentifier) obj; - return this.packageName.equals(other.packageName) - && Arrays.equals(this.certificate, other.certificate); + return this.mPackageName.equals(other.mPackageName) + && Arrays.equals(this.mSha256Certificate, other.mSha256Certificate); } @Override public int hashCode() { - return Objects.hash(packageName, Arrays.hashCode(certificate)); + return Objects.hash(mPackageName, Arrays.hashCode(mSha256Certificate)); } } 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 4ef30c3b11af..ad3ee0587f61 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java @@ -18,17 +18,14 @@ package android.app.appsearch; import android.annotation.NonNull; import android.annotation.SuppressLint; -import android.app.appsearch.exceptions.AppSearchException; import android.util.ArrayMap; import android.util.ArraySet; import com.android.internal.util.Preconditions; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Set; @@ -39,18 +36,18 @@ import java.util.Set; */ public final class SetSchemaRequest { private final Set mSchemas; - private final Set mSchemasNotPlatformSurfaceable; - private final Map> mSchemasPackageAccessible; + private final Set mSchemasNotVisibleToSystemUi; + private final Map> mSchemasVisibleToPackages; private final boolean mForceOverride; SetSchemaRequest( @NonNull Set schemas, - @NonNull Set schemasNotPlatformSurfaceable, - @NonNull Map> schemasPackageAccessible, + @NonNull Set schemasNotVisibleToSystemUi, + @NonNull Map> schemasVisibleToPackages, boolean forceOverride) { mSchemas = Preconditions.checkNotNull(schemas); - mSchemasNotPlatformSurfaceable = Preconditions.checkNotNull(schemasNotPlatformSurfaceable); - mSchemasPackageAccessible = Preconditions.checkNotNull(schemasPackageAccessible); + mSchemasNotVisibleToSystemUi = Preconditions.checkNotNull(schemasNotVisibleToSystemUi); + mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages); mForceOverride = forceOverride; } @@ -62,12 +59,11 @@ 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 getSchemasNotPlatformSurfaceable() { - return Collections.unmodifiableSet(mSchemasNotPlatformSurfaceable); + public Set getSchemasNotVisibleToSystemUi() { + return Collections.unmodifiableSet(mSchemasNotVisibleToSystemUi); } /** @@ -76,14 +72,13 @@ public final class SetSchemaRequest { * certificate. * *

This method is inefficient to call repeatedly. - * * @hide */ @NonNull - public Map> getSchemasPackageAccessible() { + public Map> getSchemasVisibleToPackages() { Map> copy = new ArrayMap<>(); - for (String key : mSchemasPackageAccessible.keySet()) { - copy.put(key, new ArraySet<>(mSchemasPackageAccessible.get(key))); + for (String key : mSchemasVisibleToPackages.keySet()) { + copy.put(key, new ArraySet<>(mSchemasVisibleToPackages.get(key))); } return copy; } @@ -93,14 +88,14 @@ public final class SetSchemaRequest { * type. Each package is represented by a {@link PackageIdentifier}. name and byte[] * certificate. * - *

A more efficient version of {@code #getSchemasPackageAccessible}, but it returns a + *

A more efficient version of {@link #getSchemasVisibleToPackages}, but it returns a * modifiable map. This is not meant to be unhidden and should only be used by internal classes. * * @hide */ @NonNull - public Map> getSchemasPackageAccessibleInternal() { - return mSchemasPackageAccessible; + public Map> getSchemasVisibleToPackagesInternal() { + return mSchemasVisibleToPackages; } /** Returns whether this request will force the schema to be overridden. */ @@ -111,8 +106,8 @@ public final class SetSchemaRequest { /** Builder for {@link SetSchemaRequest} objects. */ public static final class Builder { private final Set mSchemas = new ArraySet<>(); - private final Set mSchemasNotPlatformSurfaceable = new ArraySet<>(); - private final Map> mSchemasPackageAccessible = + private final Set mSchemasNotVisibleToSystemUi = new ArraySet<>(); + private final Map> mSchemasVisibleToPackages = new ArrayMap<>(); private boolean mForceOverride = false; private boolean mBuilt = false; @@ -148,6 +143,8 @@ public final class SetSchemaRequest { * @param visible Whether the {@code schemaType} will be visible or not. * @hide */ + // Merged list available from getSchemasNotVisibleToSystemUi + @SuppressLint("MissingGetterMatchingBuilder") @NonNull public Builder setSchemaTypeVisibilityForSystemUi( @NonNull String schemaType, boolean visible) { @@ -155,9 +152,9 @@ public final class SetSchemaRequest { Preconditions.checkState(!mBuilt, "Builder has already been used"); if (visible) { - mSchemasNotPlatformSurfaceable.remove(schemaType); + mSchemasNotVisibleToSystemUi.remove(schemaType); } else { - mSchemasNotPlatformSurfaceable.add(schemaType); + mSchemasNotVisibleToSystemUi.add(schemaType); } return this; } @@ -170,6 +167,8 @@ public final class SetSchemaRequest { * @param packageIdentifier Represents the package that will be granted visibility. * @hide */ + // Merged list available from getSchemasVisibleToPackages + @SuppressLint("MissingGetterMatchingBuilder") @NonNull public Builder setSchemaTypeVisibilityForPackage( @NonNull String schemaType, @@ -179,13 +178,13 @@ public final class SetSchemaRequest { Preconditions.checkNotNull(packageIdentifier); Preconditions.checkState(!mBuilt, "Builder has already been used"); - Set packageIdentifiers = mSchemasPackageAccessible.get(schemaType); + Set packageIdentifiers = mSchemasVisibleToPackages.get(schemaType); if (visible) { if (packageIdentifiers == null) { packageIdentifiers = new ArraySet<>(); } packageIdentifiers.add(packageIdentifier); - mSchemasPackageAccessible.put(schemaType, packageIdentifiers); + mSchemasVisibleToPackages.put(schemaType, packageIdentifiers); } else { if (packageIdentifiers == null) { // Return early since there was nothing set to begin with. @@ -194,7 +193,7 @@ public final class SetSchemaRequest { packageIdentifiers.remove(packageIdentifier); if (packageIdentifiers.isEmpty()) { // Remove the entire key so that we don't have empty sets as values. - mSchemasPackageAccessible.remove(schemaType); + mSchemasVisibleToPackages.remove(schemaType); } } @@ -229,8 +228,8 @@ public final class SetSchemaRequest { // Verify that any schema types with visibility settings refer to a real schema. // Create a copy because we're going to remove from the set for verification purposes. - Set referencedSchemas = new ArraySet<>(mSchemasNotPlatformSurfaceable); - referencedSchemas.addAll(mSchemasPackageAccessible.keySet()); + Set referencedSchemas = new ArraySet<>(mSchemasNotVisibleToSystemUi); + referencedSchemas.addAll(mSchemasVisibleToPackages.keySet()); for (AppSearchSchema schema : mSchemas) { referencedSchemas.remove(schema.getSchemaType()); @@ -244,8 +243,8 @@ public final class SetSchemaRequest { return new SetSchemaRequest( mSchemas, - mSchemasNotPlatformSurfaceable, - mSchemasPackageAccessible, + mSchemasNotVisibleToSystemUi, + mSchemasVisibleToPackages, mForceOverride); } } 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 c806af5a3be3..1d5287b1309c 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 @@ -156,7 +156,6 @@ public final class AppSearchImpl { } private AppSearchImpl(@NonNull File icingDir) throws AppSearchException { - boolean isReset = false; mReadWriteLock.writeLock().lock(); try { @@ -168,9 +167,11 @@ public final class AppSearchImpl { .build(); mIcingSearchEngineLocked = new IcingSearchEngine(options); + mVisibilityStoreLocked = new VisibilityStore(this); + InitializeResultProto initializeResultProto = mIcingSearchEngineLocked.initialize(); - SchemaProto schemaProto = null; - GetAllNamespacesResultProto getAllNamespacesResultProto = null; + SchemaProto schemaProto; + GetAllNamespacesResultProto getAllNamespacesResultProto; try { checkSuccess(initializeResultProto.getStatus()); schemaProto = getSchemaProtoLocked(); @@ -180,7 +181,7 @@ public final class AppSearchImpl { Log.w(TAG, "Error initializing, resetting IcingSearchEngine.", e); // Some error. Reset and see if it fixes it. reset(); - isReset = true; + return; } // Populate schema map @@ -196,11 +197,8 @@ public final class AppSearchImpl { // TODO(b/155939114): It's possible to optimize after init, which would reduce the time // to when we're able to serve queries. Consider moving this optimize call out. - if (!isReset) { - checkForOptimizeLocked(/* force= */ true); - } + checkForOptimizeLocked(/* force= */ true); - mVisibilityStoreLocked = new VisibilityStore(this); } finally { mReadWriteLock.writeLock().unlock(); } @@ -635,6 +633,9 @@ public final class AppSearchImpl { /** * Clears documents and schema across all packages and databaseNames. * + *

This method also clear all data in {@link VisibilityStore}, an {@link + * #initializeVisibilityStore()} must be called after this. + * *

This method belongs to mutate group. * * @throws AppSearchException on IcingSearchEngine error. diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java index 411da2fcbf8b..7e4ebb51c388 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java @@ -213,14 +213,12 @@ class VisibilityStore { } /** - * Handles an {@link AppSearchImpl#reset()} by clearing any cached state and resetting to a - * first-initialized state. + * Handles an {@code AppSearchImpl#reset()} by clearing any cached state. * - * @throws AppSearchException on AppSearchImpl error. + *

{@link #initialize()} must be called after this. */ - public void handleReset() throws AppSearchException { + void handleReset() { mNotPlatformSurfaceableMap.clear(); - initialize(); } /** diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index 5a7ab1d67cf9..f9a0bedf6183 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -Ia04e81bb574831fa7e8a26c725e53133b39ee3ef +I0577839bfddf95a555399df441d317b00c7c7c48 diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java similarity index 74% rename from apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShim.java rename to apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java index b1e760a76e41..1d2382a3be9c 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java @@ -20,15 +20,19 @@ import android.annotation.NonNull; import android.app.appsearch.AppSearchBatchResult; import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchResult; +import android.app.appsearch.AppSearchSchema; import android.app.appsearch.AppSearchSession; +import android.app.appsearch.AppSearchSessionShim; import android.app.appsearch.BatchResultCallback; import android.app.appsearch.GenericDocument; import android.app.appsearch.GetByUriRequest; import android.app.appsearch.PutDocumentsRequest; import android.app.appsearch.RemoveByUriRequest; import android.app.appsearch.SearchResults; +import android.app.appsearch.SearchResultsShim; import android.app.appsearch.SearchSpec; import android.app.appsearch.SetSchemaRequest; +import android.app.appsearch.exceptions.AppSearchException; import android.content.Context; import androidx.test.core.app.ApplicationProvider; @@ -38,6 +42,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -46,42 +51,47 @@ import java.util.concurrent.Executors; * a consistent interface. * @hide */ -public class AppSearchSessionShim { +public class AppSearchSessionShimImpl implements AppSearchSessionShim { private final AppSearchSession mAppSearchSession; private final ExecutorService mExecutor; @NonNull - public static ListenableFuture> createSearchSession( + public static ListenableFuture createSearchSession( @NonNull AppSearchManager.SearchContext searchContext) { Context context = ApplicationProvider.getApplicationContext(); AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class); SettableFuture> future = SettableFuture.create(); ExecutorService executor = Executors.newCachedThreadPool(); appSearchManager.createSearchSession(searchContext, executor, future::set); - return Futures.transform(future, (instance) -> { - if (!instance.isSuccess()) { - return AppSearchResult.newFailedResult( - instance.getResultCode(), instance.getErrorMessage()); - } - AppSearchSession searchSession = instance.getResultValue(); - AppSearchSessionShim shim = new AppSearchSessionShim(searchSession, executor); - return AppSearchResult.newSuccessfulResult(shim); - }, executor); + return Futures.transform( + future, + instance -> new AppSearchSessionShimImpl(instance.getResultValue(), executor), + executor); } - private AppSearchSessionShim( + private AppSearchSessionShimImpl( @NonNull AppSearchSession session, @NonNull ExecutorService executor) { mAppSearchSession = Preconditions.checkNotNull(session); mExecutor = Preconditions.checkNotNull(executor); } + @Override @NonNull - public ListenableFuture> setSchema(@NonNull SetSchemaRequest request) { + public ListenableFuture setSchema(@NonNull SetSchemaRequest request) { SettableFuture> future = SettableFuture.create(); mAppSearchSession.setSchema(request, mExecutor, future::set); - return future; + return Futures.transformAsync(future, this::transformResult, mExecutor); } + @Override + @NonNull + public ListenableFuture> getSchema() { + SettableFuture>> future = SettableFuture.create(); + mAppSearchSession.getSchema(mExecutor, future::set); + return Futures.transformAsync(future, this::transformResult, mExecutor); + } + + @Override @NonNull public ListenableFuture> putDocuments( @NonNull PutDocumentsRequest request) { @@ -91,6 +101,7 @@ public class AppSearchSessionShim { return future; } + @Override @NonNull public ListenableFuture> getByUri( @NonNull GetByUriRequest request) { @@ -100,14 +111,16 @@ public class AppSearchSessionShim { return future; } + @Override @NonNull public SearchResultsShim query( @NonNull String queryExpression, @NonNull SearchSpec searchSpec) { SearchResults searchResults = mAppSearchSession.query(queryExpression, searchSpec, mExecutor); - return new SearchResultsShim(searchResults); + return new SearchResultsShimImpl(searchResults, mExecutor); } + @Override @NonNull public ListenableFuture> removeByUri( @NonNull RemoveByUriRequest request) { @@ -116,12 +129,21 @@ public class AppSearchSessionShim { return future; } + @Override @NonNull - public ListenableFuture> removeByQuery( + public ListenableFuture removeByQuery( @NonNull String queryExpression, @NonNull SearchSpec searchSpec) { SettableFuture> future = SettableFuture.create(); mAppSearchSession.removeByQuery(queryExpression, searchSpec, mExecutor, future::set); - return future; + return Futures.transformAsync(future, this::transformResult, mExecutor); + } + + private ListenableFuture transformResult( + @NonNull AppSearchResult result) throws AppSearchException { + if (!result.isSuccess()) { + throw new AppSearchException(result.getResultCode(), result.getErrorMessage()); + } + return Futures.immediateFuture(result.getResultValue()); } private static final class BatchResultCallbackAdapter diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java similarity index 76% rename from apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShim.java rename to apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java index 5146426e817a..67af6b11a656 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java @@ -21,6 +21,7 @@ import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchResult; import android.app.appsearch.GlobalSearchSession; import android.app.appsearch.SearchResults; +import android.app.appsearch.SearchResultsShim; import android.app.appsearch.SearchSpec; import android.content.Context; @@ -39,30 +40,24 @@ import java.util.concurrent.Executors; * a consistent interface. * @hide */ -public class GlobalSearchSessionShim { +public class GlobalSearchSessionShimImpl { private final GlobalSearchSession mGlobalSearchSession; private final ExecutorService mExecutor; @NonNull - public static ListenableFuture> - createGlobalSearchSession() { + public static ListenableFuture createGlobalSearchSession() { Context context = ApplicationProvider.getApplicationContext(); AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class); SettableFuture> future = SettableFuture.create(); ExecutorService executor = Executors.newCachedThreadPool(); appSearchManager.createGlobalSearchSession(executor, future::set); - return Futures.transform(future, (instance) -> { - if (!instance.isSuccess()) { - return AppSearchResult.newFailedResult( - instance.getResultCode(), instance.getErrorMessage()); - } - GlobalSearchSession searchSession = instance.getResultValue(); - GlobalSearchSessionShim shim = new GlobalSearchSessionShim(searchSession, executor); - return AppSearchResult.newSuccessfulResult(shim); - }, executor); + return Futures.transform( + future, + instance -> new GlobalSearchSessionShimImpl(instance.getResultValue(), executor), + executor); } - private GlobalSearchSessionShim( + private GlobalSearchSessionShimImpl( @NonNull GlobalSearchSession session, @NonNull ExecutorService executor) { mGlobalSearchSession = Preconditions.checkNotNull(session); mExecutor = Preconditions.checkNotNull(executor); @@ -73,6 +68,6 @@ public class GlobalSearchSessionShim { @NonNull String queryExpression, @NonNull SearchSpec searchSpec) { SearchResults searchResults = mGlobalSearchSession.query(queryExpression, searchSpec, mExecutor); - return new SearchResultsShim(searchResults); + return new SearchResultsShimImpl(searchResults, mExecutor); } } diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java similarity index 73% rename from apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShim.java rename to apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java index cf434017fdb9..75add81c8d64 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShim.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/SearchResultsShimImpl.java @@ -20,31 +20,35 @@ import android.annotation.NonNull; import android.app.appsearch.AppSearchResult; import android.app.appsearch.SearchResult; import android.app.appsearch.SearchResults; +import android.app.appsearch.SearchResultsShim; import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; -import java.io.Closeable; import java.util.List; +import java.util.concurrent.Executor; /** * This test class adapts the AppSearch Framework API to ListenableFuture, so it can be tested via * a consistent interface. * @hide */ -public class SearchResultsShim implements Closeable { +public class SearchResultsShimImpl implements SearchResultsShim { + private final Executor mExecutor; private final SearchResults mSearchResults; - SearchResultsShim(@NonNull SearchResults searchResults) { + SearchResultsShimImpl(@NonNull SearchResults searchResults, @NonNull Executor executor) { + mExecutor = Preconditions.checkNotNull(executor); mSearchResults = Preconditions.checkNotNull(searchResults); } @NonNull - public ListenableFuture>> getNextPage() { + public ListenableFuture> getNextPage() { SettableFuture>> future = SettableFuture.create(); mSearchResults.getNextPage(future::set); - return future; + return Futures.transform(future, AppSearchResult::getResultValue, mExecutor); } @Override 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 new file mode 100644 index 000000000000..8c42b2dd239a --- /dev/null +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 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 android.annotation.NonNull; +import android.annotation.SuppressLint; + +import com.google.common.util.concurrent.ListenableFuture; + +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. + */ +public interface AppSearchSessionShim { + + /** + * Sets the schema that will be used by documents provided to the {@link #putDocuments} method. + * + *

The schema provided here is compared to the stored copy of the schema previously supplied + * 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: + *

    + *
  • Addition of new types + *
  • Addition of new + * {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or + * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a + * type + *
  • 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. + *
+ * + *

The following types of schema changes are not backwards-compatible: + *

    + *
  • Removal of an existing type + *
  • Removal of a property from a type + *
  • Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property + *
  • For properties of {@code Document} type, changing the schema type of + * {@code Document}s of that property + *
  • 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). + *
  • Adding a + * {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property. + *
+ *

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 + * {@link AppSearchResult#RESULT_INVALID_SCHEMA} and a message describing the incompatibility. + * In this case the previously set schema will remain active. + * + *

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. + * + *

It is a no-op to set the same schema as has been previously set; this is handled + * efficiently. + * + *

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. + * + * @param request The schema update request. + * @return The pending result of performing this operation. + */ + // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are + // exposed. + @NonNull + ListenableFuture setSchema(@NonNull SetSchemaRequest request); + + /** + * Retrieves the schema most recently successfully provided to {@link #setSchema}. + * + * @return The pending result of performing this operation. + */ + // This call hits disk; async API prevents us from treating these calls as properties. + @SuppressLint("KotlinPropertyAccess") + @NonNull + ListenableFuture> getSchema(); + + /** + * Indexes documents into AppSearch. + * + *

Each {@link GenericDocument}'s {@code schemaType} field must be set to the name of a + * 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. + */ + @NonNull + ListenableFuture> putDocuments( + @NonNull PutDocumentsRequest request); + + /** + * 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}. + */ + @NonNull + ListenableFuture> getByUri( + @NonNull GetByUriRequest request); + + /** + * Searches a document based on a given query string. + * + *

Currently we support following features in the raw query format: + *

    + *
  • AND + *

    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’ + *

  • OR + *

    OR joins (e.g. “match documents that have either the term ‘dog’ or + * ‘cat’”). + * Example: dog OR puppy + *

  • Exclusion + *

    Exclude a term (e.g. “match documents that do + * not have the term ‘dog’”). + * Example: -dog excludes the term ‘dog’ + *

  • Grouping terms + *

    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. + *

  • Property restricts + *

    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 + *

  • Schema type restricts + *

    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. + *

+ * + *

This method is lightweight. The heavy work will be done in + * {@link SearchResults#getNextPage()}. + * + * @param queryExpression Query String to search. + * @param searchSpec Spec for setting filters, raw query etc. + * @return The search result of performing this operation. + */ + @NonNull + SearchResultsShim query(@NonNull String queryExpression, @NonNull SearchSpec searchSpec); + + /** + * 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}. + */ + @NonNull + ListenableFuture> removeByUri( + @NonNull RemoveByUriRequest request); + + /** + * 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}. + * + *

An empty {@code queryExpression} matches all documents. + * + *

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. + * @return The pending result of performing this operation. + */ + @NonNull + ListenableFuture removeByQuery( + @NonNull String queryExpression, @NonNull SearchSpec searchSpec); +} diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java index 907509c5d37c..9653def204be 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java @@ -19,15 +19,11 @@ package com.android.server.appsearch.testing; import static com.google.common.truth.Truth.assertThat; import android.app.appsearch.AppSearchBatchResult; -import android.app.appsearch.AppSearchManager; -import android.app.appsearch.AppSearchResult; +import android.app.appsearch.AppSearchSessionShim; import android.app.appsearch.GenericDocument; import android.app.appsearch.GetByUriRequest; import android.app.appsearch.SearchResult; -import android.app.appsearch.SetSchemaRequest; -import android.content.Context; - -import com.google.common.collect.ImmutableList; +import android.app.appsearch.SearchResultsShim; import junit.framework.AssertionFailedError; @@ -37,32 +33,6 @@ import java.util.concurrent.Future; public class AppSearchTestUtils { - // List of databases that may be used in tests. Keeping them in a centralized location helps - // #cleanup know which databases to clear. - public static final String DEFAULT_DATABASE = AppSearchManager.DEFAULT_DATABASE_NAME; - public static final String DB_1 = "testDb1"; - public static final String DB_2 = "testDb2"; - - public static void cleanup(Context context) throws Exception { - List databases = ImmutableList.of(DEFAULT_DATABASE, DB_1, DB_2); - for (String database : databases) { - AppSearchSessionShim session = checkIsResultSuccess( - AppSearchSessionShim.createSearchSession( - new AppSearchManager.SearchContext.Builder() - .setDatabaseName(database).build())); - checkIsResultSuccess(session.setSchema( - new SetSchemaRequest.Builder().setForceOverride(true).build())); - } - } - - public static V checkIsResultSuccess(Future> future) throws Exception { - AppSearchResult result = future.get(); - if (!result.isSuccess()) { - throw new AssertionFailedError("AppSearchResult not successful: " + result); - } - return result.getResultValue(); - } - public static AppSearchBatchResult checkIsBatchResultSuccess( Future> future) throws Exception { AppSearchBatchResult result = future.get(); @@ -74,10 +44,13 @@ public class AppSearchTestUtils { public static List doGet( AppSearchSessionShim session, String namespace, String... uris) throws Exception { - AppSearchBatchResult result = checkIsBatchResultSuccess( - session.getByUri( - new GetByUriRequest.Builder() - .setNamespace(namespace).addUri(uris).build())); + AppSearchBatchResult result = + checkIsBatchResultSuccess( + session.getByUri( + new GetByUriRequest.Builder() + .setNamespace(namespace) + .addUri(uris) + .build())); assertThat(result.getSuccesses()).hasSize(uris.length); assertThat(result.getFailures()).isEmpty(); List list = new ArrayList<>(uris.length); @@ -89,13 +62,13 @@ public class AppSearchTestUtils { public static List convertSearchResultsToDocuments( SearchResultsShim searchResults) throws Exception { - List results = checkIsResultSuccess(searchResults.getNextPage()); + List results = searchResults.getNextPage().get(); List documents = new ArrayList<>(); while (results.size() > 0) { for (SearchResult result : results) { documents.add(result.getDocument()); } - results = checkIsResultSuccess(searchResults.getNextPage()); + results = searchResults.getNextPage().get(); } return documents; } 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 new file mode 100644 index 000000000000..33dc3795325b --- /dev/null +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 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 android.annotation.NonNull; + +/** + * This class provides global access to the centralized AppSearch index maintained by the system. + * + *

Apps can retrieve indexed documents through the query API. + */ +public interface GlobalSearchSessionShim { + /** + * Searches across all documents in the storage based on a given query string. + * + *

Currently we support following features in the raw query format: + *

    + *
  • AND + *

    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’ + *

  • OR + *

    OR joins (e.g. “match documents that have either the term ‘dog’ or + * ‘cat’”). + * Example: dog OR puppy + *

  • Exclusion + *

    Exclude a term (e.g. “match documents that do + * not have the term ‘dog’”). + * Example: -dog excludes the term ‘dog’ + *

  • Grouping terms + *

    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. + *

  • Property restricts + *

    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 + *

  • Schema type restricts + *

    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. + *

+ * + *

This method is lightweight. The heavy work will be done in + * {@link SearchResults#getNextPage}. + * + * @param queryExpression Query String to search. + * @param searchSpec Spec for setting filters, raw query etc. + * @return The search result of performing this operation. + */ + @NonNull + SearchResultsShim query(@NonNull String queryExpression, @NonNull SearchSpec searchSpec); +} 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 new file mode 100644 index 000000000000..f387a1740386 --- /dev/null +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/SearchResultsShim.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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 android.annotation.NonNull; + +import com.google.common.util.concurrent.ListenableFuture; + +import java.io.Closeable; +import java.util.List; + +/** + * SearchResults are a returned object from a query API. + * + *

Each {@link SearchResult} contains a document and may contain other fields like snippets + * based on request. + * + *

Should close this object after finish fetching results. + * + *

This class is not thread safe. + */ +public interface SearchResultsShim extends Closeable { + /** + * Gets a whole page of {@link SearchResult}s. + * + *

Re-call this method to get next page of {@link SearchResult}, until it returns an + * empty list. + * + *

The page size is set by + * {@link android.app.appsearch.SearchSpec.Builder#setResultCountPerPage}. + * + * @return The pending result of performing this operation. + */ + @NonNull + ListenableFuture> getNextPage(); + + @Override + void close(); +} 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 879aa0954de4..133efce58b70 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,9 +16,6 @@ package android.app.appsearch; -import static android.app.appsearch.AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES; -import static android.app.appsearch.AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN; - import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.expectThrows; @@ -27,12 +24,22 @@ import android.util.ArrayMap; import org.junit.Test; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; public class SetSchemaRequestTest { + private static Collection getSchemaTypesFromSetSchemaRequest(SetSchemaRequest request) { + HashSet schemaTypes = new HashSet<>(); + for (AppSearchSchema schema : request.getSchemas()) { + schemaTypes.add(schema.getSchemaType()); + } + return schemaTypes; + } + @Test public void testInvalidSchemaReferences_fromSystemUiVisibility() { IllegalArgumentException expected = @@ -57,7 +64,7 @@ public class SetSchemaRequestTest { /*visible=*/ true, new PackageIdentifier( "com.foo.package", - /*certificate=*/ new byte[] {})) + /*sha256Certificate=*/ new byte[] {})) .build()); assertThat(expected).hasMessageThat().contains("referenced, but were not added"); } @@ -68,14 +75,14 @@ public class SetSchemaRequestTest { // By default, the schema is visible. SetSchemaRequest request = new SetSchemaRequest.Builder().addSchema(schema).build(); - assertThat(request.getSchemasNotPlatformSurfaceable()).isEmpty(); + assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty(); request = new SetSchemaRequest.Builder() .addSchema(schema) .setSchemaTypeVisibilityForSystemUi("Schema", true) .build(); - assertThat(request.getSchemasNotPlatformSurfaceable()).isEmpty(); + assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty(); } @Test @@ -86,7 +93,7 @@ public class SetSchemaRequestTest { .addSchema(schema) .setSchemaTypeVisibilityForSystemUi("Schema", false) .build(); - assertThat(request.getSchemasNotPlatformSurfaceable()).containsExactly("Schema"); + assertThat(request.getSchemasNotVisibleToSystemUi()).containsExactly("Schema"); } @Test @@ -95,12 +102,12 @@ public class SetSchemaRequestTest { // By default, the schema is not visible. SetSchemaRequest request = new SetSchemaRequest.Builder().addSchema(schema).build(); - assertThat(request.getSchemasPackageAccessible()).isEmpty(); + assertThat(request.getSchemasVisibleToPackages()).isEmpty(); PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo", new byte[] {100}); - Map> expectedPackageVisibleMap = new ArrayMap<>(); - expectedPackageVisibleMap.put("Schema", Collections.singleton(packageIdentifier)); + Map> expectedVisibleToPackagesMap = new ArrayMap<>(); + expectedVisibleToPackagesMap.put("Schema", Collections.singleton(packageIdentifier)); request = new SetSchemaRequest.Builder() @@ -108,8 +115,8 @@ public class SetSchemaRequestTest { .setSchemaTypeVisibilityForPackage( "Schema", /*visible=*/ true, packageIdentifier) .build(); - assertThat(request.getSchemasPackageAccessible()) - .containsExactlyEntriesIn(expectedPackageVisibleMap); + assertThat(request.getSchemasVisibleToPackages()) + .containsExactlyEntriesIn(expectedVisibleToPackagesMap); } @Test @@ -123,9 +130,9 @@ public class SetSchemaRequestTest { "Schema", /*visible=*/ false, new PackageIdentifier( - "com.package.foo", /*certificate=*/ new byte[] {})) + "com.package.foo", /*sha256Certificate=*/ new byte[] {})) .build(); - assertThat(request.getSchemasPackageAccessible()).isEmpty(); + assertThat(request.getSchemasVisibleToPackages()).isEmpty(); } @Test @@ -134,8 +141,8 @@ public class SetSchemaRequestTest { PackageIdentifier packageIdentifier = new PackageIdentifier("com.package.foo", new byte[] {100}); - Map> expectedPackageVisibleMap = new ArrayMap<>(); - expectedPackageVisibleMap.put("Schema", Collections.singleton(packageIdentifier)); + Map> expectedVisibleToPackagesMap = new ArrayMap<>(); + expectedVisibleToPackagesMap.put("Schema", Collections.singleton(packageIdentifier)); SetSchemaRequest request = new SetSchemaRequest.Builder() @@ -147,8 +154,8 @@ public class SetSchemaRequestTest { .setSchemaTypeVisibilityForPackage( "Schema", /*visible=*/ true, packageIdentifier) .build(); - assertThat(request.getSchemasPackageAccessible()) - .containsExactlyEntriesIn(expectedPackageVisibleMap); + assertThat(request.getSchemasVisibleToPackages()) + .containsExactlyEntriesIn(expectedVisibleToPackagesMap); } @Test @@ -163,16 +170,16 @@ public class SetSchemaRequestTest { "Schema", /*visible=*/ true, new PackageIdentifier( - "com.package.foo", /*certificate=*/ new byte[] {100})) + "com.package.foo", /*sha256Certificate=*/ new byte[] {100})) // Then make it not visible .setSchemaTypeVisibilityForPackage( "Schema", /*visible=*/ false, new PackageIdentifier( - "com.package.foo", /*certificate=*/ new byte[] {100})) + "com.package.foo", /*sha256Certificate=*/ new byte[] {100})) .build(); // Nothing should be visible. - assertThat(request.getSchemasPackageAccessible()).isEmpty(); + assertThat(request.getSchemasVisibleToPackages()).isEmpty(); } } 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 f36ed4bf97b8..f29b0594db8f 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 @@ -75,6 +75,8 @@ public class AppSearchImplTest { SchemaToProtoConverter.toSchemaTypeConfigProto(rewrittenVisibilitySchema.build()); } + // TODO(b/175430168) add test to verify reset is working properly. + /** * Ensure that we can rewrite an incoming schema type by adding the database as a prefix. While * also keeping any other existing schema types that may already be part of Icing's persisted