Merge "Sync AppSearch from framework."
This commit is contained in:
@@ -22,6 +22,14 @@ package android.app.appsearch {
|
||||
method @NonNull public android.app.appsearch.AppSearchManager.SearchContext.Builder setDatabaseName(@NonNull String);
|
||||
}
|
||||
|
||||
public interface AppSearchMigrationHelper {
|
||||
method public void queryAndTransform(@NonNull String, @NonNull android.app.appsearch.AppSearchMigrationHelper.Transformer) throws java.lang.Exception;
|
||||
}
|
||||
|
||||
public static interface AppSearchMigrationHelper.Transformer {
|
||||
method @NonNull public android.app.appsearch.GenericDocument transform(int, int, @NonNull android.app.appsearch.GenericDocument) throws java.lang.Exception;
|
||||
}
|
||||
|
||||
public final class AppSearchResult<ValueType> {
|
||||
method @Nullable public String getErrorMessage();
|
||||
method public int getResultCode();
|
||||
@@ -99,6 +107,11 @@ package android.app.appsearch {
|
||||
method @NonNull public android.app.appsearch.AppSearchSchema.Int64PropertyConfig.Builder setCardinality(int);
|
||||
}
|
||||
|
||||
public static interface AppSearchSchema.Migrator {
|
||||
method public default void onDowngrade(int, int, @NonNull android.app.appsearch.AppSearchMigrationHelper) throws java.lang.Exception;
|
||||
method public default void onUpgrade(int, int, @NonNull android.app.appsearch.AppSearchMigrationHelper) throws java.lang.Exception;
|
||||
}
|
||||
|
||||
public abstract static class AppSearchSchema.PropertyConfig {
|
||||
method public int getCardinality();
|
||||
method public int getDataType();
|
||||
@@ -135,7 +148,7 @@ package android.app.appsearch {
|
||||
method public void removeByQuery(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
|
||||
method public void removeByUri(@NonNull android.app.appsearch.RemoveByUriRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
|
||||
method @NonNull public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
|
||||
method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
|
||||
method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
|
||||
}
|
||||
|
||||
public interface BatchResultCallback<KeyType, ValueType> {
|
||||
@@ -322,6 +335,7 @@ package android.app.appsearch {
|
||||
}
|
||||
|
||||
public final class SetSchemaRequest {
|
||||
method @NonNull public java.util.Map<java.lang.String,android.app.appsearch.AppSearchSchema.Migrator> getMigrators();
|
||||
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();
|
||||
@@ -334,10 +348,26 @@ 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 setMigrator(@NonNull String, @NonNull android.app.appsearch.AppSearchSchema.Migrator);
|
||||
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);
|
||||
}
|
||||
|
||||
public class SetSchemaResponse {
|
||||
method @NonNull public java.util.Set<java.lang.String> getDeletedTypes();
|
||||
method @NonNull public java.util.Set<java.lang.String> getIncompatibleTypes();
|
||||
method @NonNull public java.util.Set<java.lang.String> getMigratedTypes();
|
||||
method @NonNull public java.util.List<android.app.appsearch.SetSchemaResponse.MigrationFailure> getMigrationFailures();
|
||||
method public boolean isSuccess();
|
||||
}
|
||||
|
||||
public static class SetSchemaResponse.MigrationFailure {
|
||||
method @NonNull public android.app.appsearch.AppSearchResult<java.lang.Void> getAppSearchResult();
|
||||
method @NonNull public String getNamespace();
|
||||
method @NonNull public String getSchemaType();
|
||||
method @NonNull public String getUri();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.app.appsearch.exceptions {
|
||||
|
||||
@@ -162,7 +162,7 @@ public final class AppSearchSession implements Closeable {
|
||||
public void setSchema(
|
||||
@NonNull SetSchemaRequest request,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<Void>> callback) {
|
||||
@NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
@@ -192,7 +192,18 @@ public final class AppSearchSession implements Closeable {
|
||||
mUserId,
|
||||
new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
executor.execute(() -> callback.accept(result));
|
||||
executor.execute(() -> {
|
||||
if (result.isSuccess()) {
|
||||
callback.accept(
|
||||
// TODO(b/151178558) implement Migration in platform.
|
||||
AppSearchResult.newSuccessfulResult(
|
||||
new SetSchemaResponse.Builder().setResultCode(
|
||||
result.getResultCode())
|
||||
.build()));
|
||||
} else {
|
||||
callback.accept(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
mIsMutated = true;
|
||||
|
||||
65
apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java
vendored
Normal file
65
apex/appsearch/framework/java/external/android/app/appsearch/AppSearchMigrationHelper.java
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.appsearch;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
/**
|
||||
* The helper class for {@link AppSearchSchema} migration.
|
||||
*
|
||||
* <p>It will query and migrate {@link GenericDocument} in given type to a new version.
|
||||
*/
|
||||
public interface AppSearchMigrationHelper {
|
||||
|
||||
/**
|
||||
* Queries all documents that need to be migrated to the different version, and transform
|
||||
* documents to that version by passing them to the provided {@link Transformer}.
|
||||
*
|
||||
* @param schemaType The schema that need be updated and migrated {@link GenericDocument} under
|
||||
* this type.
|
||||
* @param transformer The {@link Transformer} that will upgrade or downgrade a {@link
|
||||
* GenericDocument} to new version.
|
||||
* @see Transformer#transform
|
||||
*/
|
||||
// Rethrow the Generic Exception thrown from the Transformer.
|
||||
@SuppressLint("GenericException")
|
||||
void queryAndTransform(@NonNull String schemaType, @NonNull Transformer transformer)
|
||||
throws Exception;
|
||||
|
||||
/** The class to migrate {@link GenericDocument} between different version. */
|
||||
interface Transformer {
|
||||
|
||||
/**
|
||||
* Translates a {@link GenericDocument} from a version to a different version.
|
||||
*
|
||||
* <p>If the uri, schema type or namespace is changed via the transform, it will apply to
|
||||
* the new {@link GenericDocument}.
|
||||
*
|
||||
* @param currentVersion The current version of the document's schema.
|
||||
* @param finalVersion The final version that documents need to be migrated to.
|
||||
* @param document The {@link GenericDocument} need to be translated to new version.
|
||||
* @return A {@link GenericDocument} in new version.
|
||||
*/
|
||||
@NonNull
|
||||
// This method will be overridden by users, allow them to throw any customer Exceptions.
|
||||
@SuppressLint("GenericException")
|
||||
GenericDocument transform(
|
||||
int currentVersion, int finalVersion, @NonNull GenericDocument document)
|
||||
throws Exception;
|
||||
}
|
||||
}
|
||||
@@ -164,10 +164,10 @@ public final class AppSearchSchema {
|
||||
* a {@link AppSearchSchema} type at a time.
|
||||
*
|
||||
* <p>Setting a version number that is different from the version number of the schema
|
||||
* currently stored in AppSearch will result in AppSearch calling the Migrator provided to
|
||||
* {@link AppSearchSession#setSchema} to migrate the documents already in AppSearch from the
|
||||
* previous version to the one set in this request. The version number can be updated
|
||||
* without any other changes to the schema.
|
||||
* currently stored in AppSearch will result in AppSearch calling the {@link Migrator}
|
||||
* provided to {@link AppSearchSession#setSchema} to migrate the documents already in
|
||||
* AppSearch from the previous version to the one set in this request. The version number
|
||||
* can be updated without any other changes to the schema.
|
||||
*
|
||||
* <p>The version number can stay the same, increase, or decrease relative to the current
|
||||
* version number of the {@link AppSearchSchema} type that is already stored in the {@link
|
||||
@@ -182,8 +182,9 @@ public final class AppSearchSchema {
|
||||
* @throws IllegalStateException if the version is negative or the builder has already been
|
||||
* used.
|
||||
* @see AppSearchSession#setSchema
|
||||
* @see AppSearchSchema.Migrator
|
||||
* @see SetSchemaRequest.Builder#setMigrator
|
||||
*/
|
||||
// TODO(b/177266929) link to Migrator in once it's ready.
|
||||
@NonNull
|
||||
public AppSearchSchema.Builder setVersion(@IntRange(from = 0) int version) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
@@ -859,4 +860,43 @@ public final class AppSearchSchema {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A migrator class to translate {@link GenericDocument} from different version of {@link
|
||||
* AppSearchSchema}
|
||||
*/
|
||||
public interface Migrator {
|
||||
|
||||
/**
|
||||
* Migrates {@link GenericDocument} to a newer version of {@link AppSearchSchema}.
|
||||
*
|
||||
* <p>This methods will be invoked only if the {@link SetSchemaRequest} is setting a higher
|
||||
* version number than the current {@link AppSearchSchema} saved in AppSearch.
|
||||
*
|
||||
* @param currentVersion The current version of the document's schema.
|
||||
* @param targetVersion The final version that documents need to be migrated to.
|
||||
* @param helper The helper class could help to query all documents need to be migrated.
|
||||
*/
|
||||
// This method will be overridden by users, allow them to throw any customer Exceptions.
|
||||
@SuppressLint("GenericException")
|
||||
default void onUpgrade(
|
||||
int currentVersion, int targetVersion, @NonNull AppSearchMigrationHelper helper)
|
||||
throws Exception {}
|
||||
|
||||
/**
|
||||
* Migrates {@link GenericDocument} to an older version of {@link AppSearchSchema}.
|
||||
*
|
||||
* <p>The methods will be invoked only if the {@link SetSchemaRequest} is setting a higher
|
||||
* version number than the current {@link AppSearchSchema} saved in AppSearch.
|
||||
*
|
||||
* @param currentVersion The current version of the document's schema.
|
||||
* @param targetVersion The final version that documents need to be migrated to.
|
||||
* @param helper The helper class could help to query all documents need to be migrated.
|
||||
*/
|
||||
// This method will be overridden by users, allow them to throw any customer Exceptions.
|
||||
@SuppressLint("GenericException")
|
||||
default void onDowngrade(
|
||||
int currentVersion, int targetVersion, @NonNull AppSearchMigrationHelper helper)
|
||||
throws Exception {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,16 +38,19 @@ public final class SetSchemaRequest {
|
||||
private final Set<AppSearchSchema> mSchemas;
|
||||
private final Set<String> mSchemasNotVisibleToSystemUi;
|
||||
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages;
|
||||
private final Map<String, AppSearchSchema.Migrator> mMigrators;
|
||||
private final boolean mForceOverride;
|
||||
|
||||
SetSchemaRequest(
|
||||
@NonNull Set<AppSearchSchema> schemas,
|
||||
@NonNull Set<String> schemasNotVisibleToSystemUi,
|
||||
@NonNull Map<String, Set<PackageIdentifier>> schemasVisibleToPackages,
|
||||
@NonNull Map<String, AppSearchSchema.Migrator> migrators,
|
||||
boolean forceOverride) {
|
||||
mSchemas = Preconditions.checkNotNull(schemas);
|
||||
mSchemasNotVisibleToSystemUi = Preconditions.checkNotNull(schemasNotVisibleToSystemUi);
|
||||
mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
|
||||
mMigrators = Preconditions.checkNotNull(migrators);
|
||||
mForceOverride = forceOverride;
|
||||
}
|
||||
|
||||
@@ -81,6 +84,12 @@ public final class SetSchemaRequest {
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Returns the map of {@link android.app.appsearch.AppSearchSchema.Migrator}. */
|
||||
@NonNull
|
||||
public Map<String, AppSearchSchema.Migrator> getMigrators() {
|
||||
return Collections.unmodifiableMap(mMigrators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mapping of schema types to the set of packages that have access to that schema
|
||||
* type. Each package is represented by a {@link PackageIdentifier}. name and byte[]
|
||||
@@ -107,6 +116,7 @@ public final class SetSchemaRequest {
|
||||
private final Set<String> mSchemasNotVisibleToSystemUi = new ArraySet<>();
|
||||
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
|
||||
new ArrayMap<>();
|
||||
private final Map<String, AppSearchSchema.Migrator> mMigrators = new ArrayMap<>();
|
||||
private boolean mForceOverride = false;
|
||||
private boolean mBuilt = false;
|
||||
|
||||
@@ -196,6 +206,23 @@ public final class SetSchemaRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link android.app.appsearch.AppSearchSchema.Migrator}.
|
||||
*
|
||||
* @param schemaType The schema type to set migrator on.
|
||||
* @param migrator The migrator translate a document from it's old version to a new
|
||||
* incompatible version.
|
||||
*/
|
||||
@NonNull
|
||||
@SuppressLint("MissingGetterMatchingBuilder") // Getter return plural objects.
|
||||
public Builder setMigrator(
|
||||
@NonNull String schemaType, @NonNull AppSearchSchema.Migrator migrator) {
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Preconditions.checkNotNull(migrator);
|
||||
mMigrators.put(schemaType, migrator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link SetSchemaRequest} to delete any existing documents that don't
|
||||
* follow the new schema.
|
||||
@@ -241,6 +268,7 @@ public final class SetSchemaRequest {
|
||||
mSchemas,
|
||||
mSchemasNotVisibleToSystemUi,
|
||||
mSchemasVisibleToPackages,
|
||||
mMigrators,
|
||||
mForceOverride);
|
||||
}
|
||||
}
|
||||
|
||||
258
apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
vendored
Normal file
258
apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.appsearch;
|
||||
|
||||
import static android.app.appsearch.AppSearchResult.RESULT_OK;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** The response class of {@link AppSearchSession#setSchema} */
|
||||
public class SetSchemaResponse {
|
||||
private final List<MigrationFailure> mMigrationFailures;
|
||||
private final Set<String> mDeletedTypes;
|
||||
private final Set<String> mMigratedTypes;
|
||||
private final Set<String> mIncompatibleTypes;
|
||||
private final @AppSearchResult.ResultCode int mResultCode;
|
||||
|
||||
SetSchemaResponse(
|
||||
@NonNull List<MigrationFailure> migrationFailures,
|
||||
@NonNull Set<String> deletedTypes,
|
||||
@NonNull Set<String> migratedTypes,
|
||||
@NonNull Set<String> incompatibleTypes,
|
||||
@AppSearchResult.ResultCode int resultCode) {
|
||||
mMigrationFailures = Preconditions.checkNotNull(migrationFailures);
|
||||
mDeletedTypes = Preconditions.checkNotNull(deletedTypes);
|
||||
mMigratedTypes = Preconditions.checkNotNull(migratedTypes);
|
||||
mIncompatibleTypes = Preconditions.checkNotNull(incompatibleTypes);
|
||||
mResultCode = resultCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link List} of all failed {@link MigrationFailure}.
|
||||
*
|
||||
* <p>A {@link MigrationFailure} will be generated if the system trying to save a post-migrated
|
||||
* {@link GenericDocument} but fail.
|
||||
*
|
||||
* <p>{@link MigrationFailure} contains the uri, namespace and schemaType of the post-migrated
|
||||
* {@link GenericDocument} and the error reason. Mostly it will be mismatch the schema it
|
||||
* migrated to.
|
||||
*/
|
||||
@NonNull
|
||||
public List<MigrationFailure> getMigrationFailures() {
|
||||
return Collections.unmodifiableList(mMigrationFailures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} of schema type that were deleted by the {@link
|
||||
* AppSearchSession#setSchema} call.
|
||||
*/
|
||||
@NonNull
|
||||
public Set<String> getDeletedTypes() {
|
||||
return Collections.unmodifiableSet(mDeletedTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} of schema type that were migrated by the {@link
|
||||
* AppSearchSession#setSchema} call.
|
||||
*/
|
||||
@NonNull
|
||||
public Set<String> getMigratedTypes() {
|
||||
return Collections.unmodifiableSet(mMigratedTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} of schema type whose new definitions set in the {@link
|
||||
* AppSearchSession#setSchema} call were incompatible with the pre-existing schema.
|
||||
*
|
||||
* <p>If a {@link android.app.appsearch.AppSearchSchema.Migrator} is provided for this type and
|
||||
* the migration is success triggered. The type will also appear in {@link #getMigratedTypes()}.
|
||||
*
|
||||
* @see AppSearchSession#setSchema
|
||||
* @see SetSchemaRequest.Builder#setForceOverride
|
||||
*/
|
||||
@NonNull
|
||||
public Set<String> getIncompatibleTypes() {
|
||||
return Collections.unmodifiableSet(mIncompatibleTypes);
|
||||
}
|
||||
|
||||
/** Returns {@code true} if all {@link AppSearchSchema}s are successful set to the system. */
|
||||
public boolean isSuccess() {
|
||||
return mResultCode == RESULT_OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public String toString() {
|
||||
return "{\n Does setSchema success? : "
|
||||
+ isSuccess()
|
||||
+ "\n failures: "
|
||||
+ mMigrationFailures
|
||||
+ "\n}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link SetSchemaResponse} objects.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class Builder {
|
||||
private final List<MigrationFailure> mMigrationFailures = new ArrayList<>();
|
||||
private final Set<String> mDeletedTypes = new ArraySet<>();
|
||||
private final Set<String> mMigratedTypes = new ArraySet<>();
|
||||
private final Set<String> mIncompatibleTypes = new ArraySet<>();
|
||||
private @AppSearchResult.ResultCode int mResultCode = RESULT_OK;
|
||||
private boolean mBuilt = false;
|
||||
|
||||
/** Adds a {@link MigrationFailure}. */
|
||||
@NonNull
|
||||
public Builder setFailure(
|
||||
@NonNull String schemaType,
|
||||
@NonNull String namespace,
|
||||
@NonNull String uri,
|
||||
@NonNull AppSearchResult<Void> failureResult) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Preconditions.checkNotNull(schemaType);
|
||||
Preconditions.checkNotNull(namespace);
|
||||
Preconditions.checkNotNull(uri);
|
||||
Preconditions.checkNotNull(failureResult);
|
||||
Preconditions.checkState(!failureResult.isSuccess());
|
||||
mMigrationFailures.add(new MigrationFailure(schemaType, namespace, uri, failureResult));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds a {@link MigrationFailure}. */
|
||||
@NonNull
|
||||
public Builder setFailure(
|
||||
@NonNull String schemaType,
|
||||
@NonNull String namespace,
|
||||
@NonNull String uri,
|
||||
@AppSearchResult.ResultCode int resultCode,
|
||||
@Nullable String errorMessage) {
|
||||
mMigrationFailures.add(
|
||||
new MigrationFailure(
|
||||
schemaType,
|
||||
namespace,
|
||||
uri,
|
||||
AppSearchResult.newFailedResult(resultCode, errorMessage)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds deletedTypes to the list of deleted schema types. */
|
||||
@NonNull
|
||||
public Builder addDeletedType(@NonNull Collection<String> deletedTypes) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mDeletedTypes.addAll(Preconditions.checkNotNull(deletedTypes));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds incompatibleTypes to the list of incompatible schema types. */
|
||||
@NonNull
|
||||
public Builder addIncompatibleType(@NonNull Collection<String> incompatibleTypes) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mIncompatibleTypes.addAll(Preconditions.checkNotNull(incompatibleTypes));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds migratedTypes to the list of migrated schema types. */
|
||||
@NonNull
|
||||
public Builder addMigratedType(@NonNull String migratedType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mMigratedTypes.add(Preconditions.checkNotNull(migratedType));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the {@link AppSearchResult.ResultCode} of the response. */
|
||||
@NonNull
|
||||
public Builder setResultCode(@AppSearchResult.ResultCode int resultCode) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mResultCode = resultCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a {@link SetSchemaResponse} object. */
|
||||
@NonNull
|
||||
public SetSchemaResponse build() {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mBuilt = true;
|
||||
return new SetSchemaResponse(
|
||||
mMigrationFailures,
|
||||
mDeletedTypes,
|
||||
mMigratedTypes,
|
||||
mIncompatibleTypes,
|
||||
mResultCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class represents a post-migrated {@link GenericDocument} that failed to be saved by
|
||||
* {@link AppSearchSession#setSchema}.
|
||||
*/
|
||||
public static class MigrationFailure {
|
||||
private final String mSchemaType;
|
||||
private final String mNamespace;
|
||||
private final String mUri;
|
||||
AppSearchResult<Void> mFailureResult;
|
||||
|
||||
MigrationFailure(
|
||||
@NonNull String schemaType,
|
||||
@NonNull String namespace,
|
||||
@NonNull String uri,
|
||||
@NonNull AppSearchResult<Void> result) {
|
||||
mSchemaType = schemaType;
|
||||
mNamespace = namespace;
|
||||
mUri = uri;
|
||||
mFailureResult = result;
|
||||
}
|
||||
|
||||
/** Returns the schema type of the {@link GenericDocument} that fails to be migrated. */
|
||||
@NonNull
|
||||
public String getSchemaType() {
|
||||
return mSchemaType;
|
||||
}
|
||||
|
||||
/** Returns the namespace of the {@link GenericDocument} that fails to be migrated. */
|
||||
@NonNull
|
||||
public String getNamespace() {
|
||||
return mNamespace;
|
||||
}
|
||||
|
||||
/** Returns the uri of the {@link GenericDocument} that fails to be migrated. */
|
||||
@NonNull
|
||||
public String getUri() {
|
||||
return mUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AppSearchResult} that indicates why the post-migrated {@link
|
||||
* GenericDocument} fails to be saved.
|
||||
*/
|
||||
@NonNull
|
||||
public AppSearchResult<Void> getAppSearchResult() {
|
||||
return mFailureResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
125
apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResult.java
vendored
Normal file
125
apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResult.java
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.appsearch;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the results of setSchema().
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SetSchemaResult {
|
||||
|
||||
public static final String DELETED_SCHEMA_TYPES_FIELD = "deletedSchemaTypes";
|
||||
public static final String INCOMPATIBLE_SCHEMA_TYPES_FIELD = "incompatibleSchemaTypes";
|
||||
public static final String RESULT_CODE_FIELD = "resultCode";
|
||||
private final List<String> mDeletedSchemaTypes;
|
||||
private final List<String> mIncompatibleSchemaTypes;
|
||||
private final Bundle mBundle;
|
||||
|
||||
SetSchemaResult(@NonNull Bundle bundle) {
|
||||
mBundle = Preconditions.checkNotNull(bundle);
|
||||
mDeletedSchemaTypes =
|
||||
Preconditions.checkNotNull(mBundle.getStringArrayList(DELETED_SCHEMA_TYPES_FIELD));
|
||||
mIncompatibleSchemaTypes =
|
||||
Preconditions.checkNotNull(
|
||||
mBundle.getStringArrayList(INCOMPATIBLE_SCHEMA_TYPES_FIELD));
|
||||
}
|
||||
|
||||
/** Returns the {@link Bundle} of this class. */
|
||||
@NonNull
|
||||
public Bundle getBundle() {
|
||||
return mBundle;
|
||||
}
|
||||
|
||||
/** returns all deleted schema types in this setSchema call. */
|
||||
@NonNull
|
||||
public List<String> getDeletedSchemaTypes() {
|
||||
return Collections.unmodifiableList(mDeletedSchemaTypes);
|
||||
}
|
||||
|
||||
/** returns all incompatible schema types in this setSchema call. */
|
||||
@NonNull
|
||||
public List<String> getIncompatibleSchemaTypes() {
|
||||
return Collections.unmodifiableList(mIncompatibleSchemaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the {@link android.app.appsearch.AppSearchResult.ResultCode} of the {@link
|
||||
* AppSearchSession#setSchema} call.
|
||||
*/
|
||||
public int getResultCode() {
|
||||
return mBundle.getInt(RESULT_CODE_FIELD);
|
||||
}
|
||||
|
||||
/** Builder for {@link SetSchemaResult} objects. */
|
||||
public static final class Builder {
|
||||
private final ArrayList<String> mDeletedSchemaTypes = new ArrayList<>();
|
||||
private final ArrayList<String> mIncompatibleSchemaTypes = new ArrayList<>();
|
||||
@AppSearchResult.ResultCode private int mResultCode;
|
||||
private boolean mBuilt = false;
|
||||
|
||||
/** Adds a deletedSchemaTypes to the {@link SetSchemaResult}. */
|
||||
@NonNull
|
||||
public Builder addDeletedSchemaType(@NonNull String deletedSchemaType) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mDeletedSchemaTypes.add(Preconditions.checkNotNull(deletedSchemaType));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds a incompatible SchemaTypes to the {@link SetSchemaResult}. */
|
||||
@NonNull
|
||||
public Builder addIncompatibleSchemaType(@NonNull String incompatibleSchemaTypes) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mIncompatibleSchemaTypes.add(Preconditions.checkNotNull(incompatibleSchemaTypes));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link android.app.appsearch.AppSearchResult.ResultCode} of the {@link
|
||||
* AppSearchSession#setSchema} call to the {@link SetSchemaResult}
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setResultCode(@AppSearchResult.ResultCode int resultCode) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mResultCode = resultCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a {@link SetSchemaResult}. */
|
||||
@NonNull
|
||||
public SetSchemaResult build() {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putStringArrayList(
|
||||
SetSchemaResult.DELETED_SCHEMA_TYPES_FIELD, mDeletedSchemaTypes);
|
||||
bundle.putStringArrayList(
|
||||
SetSchemaResult.INCOMPATIBLE_SCHEMA_TYPES_FIELD, mIncompatibleSchemaTypes);
|
||||
bundle.putInt(RESULT_CODE_FIELD, mResultCode);
|
||||
mBuilt = true;
|
||||
return new SetSchemaResult(bundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import android.app.appsearch.GetByUriRequest;
|
||||
import android.app.appsearch.PackageIdentifier;
|
||||
import android.app.appsearch.SearchResultPage;
|
||||
import android.app.appsearch.SearchSpec;
|
||||
import android.app.appsearch.SetSchemaResult;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
@@ -36,9 +37,11 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.ResultCodeToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.SearchResultToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.SetSchemaResultToProtoConverter;
|
||||
import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter;
|
||||
|
||||
import com.google.android.icing.IcingSearchEngine;
|
||||
@@ -259,7 +262,8 @@ public final class AppSearchImpl {
|
||||
* which do not comply with the new schema will be deleted.
|
||||
* @throws AppSearchException on IcingSearchEngine error.
|
||||
*/
|
||||
public void setSchema(
|
||||
@NonNull
|
||||
public SetSchemaResult setSchema(
|
||||
@NonNull String packageName,
|
||||
@NonNull String databaseName,
|
||||
@NonNull List<AppSearchSchema> schemas,
|
||||
@@ -273,8 +277,9 @@ public final class AppSearchImpl {
|
||||
|
||||
SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
|
||||
for (int i = 0; i < schemas.size(); i++) {
|
||||
AppSearchSchema schema = schemas.get(i);
|
||||
SchemaTypeConfigProto schemaTypeProto =
|
||||
SchemaToProtoConverter.toSchemaTypeConfigProto(schemas.get(i));
|
||||
SchemaToProtoConverter.toSchemaTypeConfigProto(schema);
|
||||
newSchemaBuilder.addTypes(schemaTypeProto);
|
||||
}
|
||||
|
||||
@@ -293,16 +298,10 @@ public final class AppSearchImpl {
|
||||
try {
|
||||
checkSuccess(setSchemaResultProto.getStatus());
|
||||
} catch (AppSearchException e) {
|
||||
// Improve the error message by merging in information about incompatible types.
|
||||
if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
|
||||
|| setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0) {
|
||||
String newMessage =
|
||||
e.getMessage()
|
||||
+ "\n Deleted types: "
|
||||
+ setSchemaResultProto.getDeletedSchemaTypesList()
|
||||
+ "\n Incompatible types: "
|
||||
+ setSchemaResultProto.getIncompatibleSchemaTypesList();
|
||||
throw new AppSearchException(e.getResultCode(), newMessage, e.getCause());
|
||||
return SetSchemaResultToProtoConverter.toSetSchemaResult(
|
||||
setSchemaResultProto, prefix);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
@@ -339,6 +338,7 @@ public final class AppSearchImpl {
|
||||
// incompatible schemas.
|
||||
checkForOptimizeLocked(/* force= */ true);
|
||||
}
|
||||
return SetSchemaResultToProtoConverter.toSetSchemaResult(setSchemaResultProto, prefix);
|
||||
} finally {
|
||||
mReadWriteLock.writeLock().unlock();
|
||||
}
|
||||
@@ -796,6 +796,8 @@ public final class AppSearchImpl {
|
||||
* <p>If the app crashes before a call to PersistToDisk(), Icing would trigger a costly recovery
|
||||
* process in next initialization. After that, Icing would still be able to recover all written
|
||||
* data.
|
||||
*
|
||||
* @throws AppSearchException on any error that AppSearch persist data to disk.
|
||||
*/
|
||||
public void persistToDisk() throws AppSearchException {
|
||||
PersistToDiskResultProto persistToDiskResultProto =
|
||||
@@ -1374,28 +1376,8 @@ public final class AppSearchImpl {
|
||||
* @return AppSearchException with the parallel error code.
|
||||
*/
|
||||
private static AppSearchException statusProtoToAppSearchException(StatusProto statusProto) {
|
||||
switch (statusProto.getCode()) {
|
||||
case INVALID_ARGUMENT:
|
||||
return new AppSearchException(
|
||||
AppSearchResult.RESULT_INVALID_ARGUMENT, statusProto.getMessage());
|
||||
case NOT_FOUND:
|
||||
return new AppSearchException(
|
||||
AppSearchResult.RESULT_NOT_FOUND, statusProto.getMessage());
|
||||
case FAILED_PRECONDITION:
|
||||
// Fallthrough
|
||||
case ABORTED:
|
||||
// Fallthrough
|
||||
case INTERNAL:
|
||||
return new AppSearchException(
|
||||
AppSearchResult.RESULT_INTERNAL_ERROR, statusProto.getMessage());
|
||||
case OUT_OF_SPACE:
|
||||
return new AppSearchException(
|
||||
AppSearchResult.RESULT_OUT_OF_SPACE, statusProto.getMessage());
|
||||
default:
|
||||
// Some unknown/unsupported error
|
||||
return new AppSearchException(
|
||||
AppSearchResult.RESULT_UNKNOWN_ERROR,
|
||||
"Unknown IcingSearchEngine status code: " + statusProto.getCode());
|
||||
}
|
||||
return new AppSearchException(
|
||||
ResultCodeToProtoConverter.toResultCode(statusProto.getCode()),
|
||||
statusProto.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.appsearch.external.localstorage.converter;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.icing.proto.StatusProto;
|
||||
|
||||
/**
|
||||
* Translates an {@link StatusProto.Code} into a {@link AppSearchResult.ResultCode}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class ResultCodeToProtoConverter {
|
||||
|
||||
private static final String TAG = "AppSearchResultCodeToPr";
|
||||
|
||||
private ResultCodeToProtoConverter() {}
|
||||
|
||||
/** Converts an {@link StatusProto.Code} into a {@link AppSearchResult.ResultCode}. */
|
||||
public static @AppSearchResult.ResultCode int toResultCode(
|
||||
@NonNull StatusProto.Code statusCode) {
|
||||
switch (statusCode) {
|
||||
case OK:
|
||||
return AppSearchResult.RESULT_OK;
|
||||
case OUT_OF_SPACE:
|
||||
return AppSearchResult.RESULT_OUT_OF_SPACE;
|
||||
case INTERNAL:
|
||||
return AppSearchResult.RESULT_INTERNAL_ERROR;
|
||||
case UNKNOWN:
|
||||
return AppSearchResult.RESULT_UNKNOWN_ERROR;
|
||||
case NOT_FOUND:
|
||||
return AppSearchResult.RESULT_NOT_FOUND;
|
||||
case INVALID_ARGUMENT:
|
||||
return AppSearchResult.RESULT_INVALID_ARGUMENT;
|
||||
default:
|
||||
// Some unknown/unsupported error
|
||||
Log.e(
|
||||
TAG,
|
||||
"Cannot convert IcingSearchEngine status code: "
|
||||
+ statusCode
|
||||
+ " to AppSearchResultCode.");
|
||||
return AppSearchResult.RESULT_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.appsearch.external.localstorage.converter;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.SetSchemaResult;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import com.google.android.icing.proto.SetSchemaResultProto;
|
||||
|
||||
/**
|
||||
* Translates a {@link SetSchemaResultProto} into {@link SetSchemaResult}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SetSchemaResultToProtoConverter {
|
||||
|
||||
private SetSchemaResultToProtoConverter() {}
|
||||
|
||||
/**
|
||||
* Translate a {@link SetSchemaResultProto} into {@link SetSchemaResult}.
|
||||
*
|
||||
* @param proto The {@link SetSchemaResultProto} containing results.
|
||||
* @param prefix The prefix need to removed from schemaTypes
|
||||
* @return {@link SetSchemaResult} of results.
|
||||
*/
|
||||
@NonNull
|
||||
public static SetSchemaResult toSetSchemaResult(
|
||||
@NonNull SetSchemaResultProto proto, @NonNull String prefix) {
|
||||
Preconditions.checkNotNull(proto);
|
||||
Preconditions.checkNotNull(prefix);
|
||||
SetSchemaResult.Builder builder =
|
||||
new SetSchemaResult.Builder()
|
||||
.setResultCode(
|
||||
ResultCodeToProtoConverter.toResultCode(
|
||||
proto.getStatus().getCode()));
|
||||
|
||||
for (int i = 0; i < proto.getDeletedSchemaTypesCount(); i++) {
|
||||
builder.addDeletedSchemaType(proto.getDeletedSchemaTypes(i).substring(prefix.length()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < proto.getIncompatibleSchemaTypesCount(); i++) {
|
||||
builder.addIncompatibleSchemaType(
|
||||
proto.getIncompatibleSchemaTypes(i).substring(prefix.length()));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
I03df55376689c1557c651d5b9671c40da1c35955
|
||||
I3fd4c96bf775c2539d744c416cdbf1d3c9544f03
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.app.appsearch.SearchResults;
|
||||
import android.app.appsearch.SearchResultsShim;
|
||||
import android.app.appsearch.SearchSpec;
|
||||
import android.app.appsearch.SetSchemaRequest;
|
||||
import android.app.appsearch.SetSchemaResponse;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.content.Context;
|
||||
|
||||
@@ -85,8 +86,8 @@ public class AppSearchSessionShimImpl implements AppSearchSessionShim {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ListenableFuture<Void> setSchema(@NonNull SetSchemaRequest request) {
|
||||
SettableFuture<AppSearchResult<Void>> future = SettableFuture.create();
|
||||
public ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request) {
|
||||
SettableFuture<AppSearchResult<SetSchemaResponse>> future = SettableFuture.create();
|
||||
mAppSearchSession.setSchema(request, mExecutor, future::set);
|
||||
return Futures.transformAsync(future, this::transformResult, mExecutor);
|
||||
}
|
||||
@@ -159,6 +160,16 @@ public class AppSearchSessionShimImpl implements AppSearchSessionShim {
|
||||
mAppSearchSession.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ListenableFuture<Void> maybeFlush() {
|
||||
SettableFuture<AppSearchResult<Void>> future = SettableFuture.create();
|
||||
// The data in platform will be flushed by scheduled task. AppSearchSession won't do
|
||||
// anything extra flush.
|
||||
future.set(AppSearchResult.newSuccessfulResult(null));
|
||||
return Futures.transformAsync(future, this::transformResult, mExecutor);
|
||||
}
|
||||
|
||||
private <T> ListenableFuture<T> transformResult(
|
||||
@NonNull AppSearchResult<T> result) throws AppSearchException {
|
||||
if (!result.isSuccess()) {
|
||||
|
||||
@@ -69,12 +69,19 @@ public interface AppSearchSessionShim extends Closeable {
|
||||
* {@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
|
||||
* 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>If you need to make non-backwards-compatible changes as described above, you can either:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Set the {@link SetSchemaRequest.Builder#setForceOverride} method to {@code true}. In
|
||||
* this case, 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.
|
||||
* <li>Add a {@link android.app.appsearch.AppSearchSchema.Migrator} for each incompatible type
|
||||
* and make no deletion. The migrator will migrate documents from it's old schema version
|
||||
* to the new version. See the migration section below.
|
||||
* </ul>
|
||||
*
|
||||
* <p>It is a no-op to set the same schema as has been previously set; this is handled
|
||||
* efficiently.
|
||||
@@ -85,13 +92,34 @@ public interface AppSearchSessionShim extends Closeable {
|
||||
* Visibility settings for a schema type do not apply or persist across {@link
|
||||
* SetSchemaRequest}s.
|
||||
*
|
||||
* <p>Migration: make non-backwards-compatible changes will delete all stored documents in old
|
||||
* schema. You can save your documents by setting {@link
|
||||
* android.app.appsearch.AppSearchSchema.Migrator} via the {@link
|
||||
* SetSchemaRequest.Builder#setMigrator} for each type you want to save.
|
||||
*
|
||||
* <p>{@link android.app.appsearch.AppSearchSchema.Migrator#onDowngrade} or {@link
|
||||
* android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} will be triggered if the version
|
||||
* number of the schema stored in AppSearch is different with the version in the request.
|
||||
*
|
||||
* <p>If any error or Exception occurred in the {@link
|
||||
* android.app.appsearch.AppSearchSchema.Migrator#onDowngrade}, {@link
|
||||
* android.app.appsearch.AppSearchSchema.Migrator#onUpgrade} or {@link
|
||||
* android.app.appsearch.AppSearchMigrationHelper.Transformer#transform}, the migration will be
|
||||
* terminated, the setSchema request will be rejected unless the schema changes are
|
||||
* backwards-compatible, and stored documents won't have any observable changes.
|
||||
*
|
||||
* @param request The schema update request.
|
||||
* @return The pending result of performing this operation.
|
||||
* @return The pending {@link SetSchemaResponse} of performing this operation. Success if the
|
||||
* the schema has been set and any migrations has been done. Otherwise, the failure {@link
|
||||
* android.app.appsearch.SetSchemaResponse.MigrationFailure} indicates which document is
|
||||
* fail to be migrated.
|
||||
* @see android.app.appsearch.AppSearchSchema.Migrator
|
||||
* @see android.app.appsearch.AppSearchMigrationHelper.Transformer
|
||||
*/
|
||||
// TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
|
||||
// exposed.
|
||||
@NonNull
|
||||
ListenableFuture<Void> setSchema(@NonNull SetSchemaRequest request);
|
||||
ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request);
|
||||
|
||||
/**
|
||||
* Retrieves the schema most recently successfully provided to {@link #setSchema}.
|
||||
@@ -226,6 +254,17 @@ public interface AppSearchSessionShim extends Closeable {
|
||||
ListenableFuture<Void> removeByQuery(
|
||||
@NonNull String queryExpression, @NonNull SearchSpec searchSpec);
|
||||
|
||||
/**
|
||||
* Flush all schema and document updates, additions, and deletes to disk if possible.
|
||||
*
|
||||
* @return The pending result of performing this operation. {@link
|
||||
* android.app.appsearch.exceptions.AppSearchException} with {@link
|
||||
* AppSearchResult#RESULT_INTERNAL_ERROR} will be set to the future if we hit error when
|
||||
* save to disk.
|
||||
*/
|
||||
@NonNull
|
||||
ListenableFuture<Void> maybeFlush();
|
||||
|
||||
/**
|
||||
* Closes the {@link AppSearchSessionShim} to persist all schema and document updates,
|
||||
* additions, and deletes to disk.
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.app.appsearch.GenericDocument;
|
||||
import android.app.appsearch.GetByUriRequest;
|
||||
import android.app.appsearch.SearchResult;
|
||||
import android.app.appsearch.SearchResultsShim;
|
||||
import android.app.appsearch.SetSchemaResponse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -42,6 +43,15 @@ public class AppSearchTestUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(b/151178558) check setSchemaResponse.xxxtypes for the test need to verify.
|
||||
public static void checkIsSetSchemaResponseSuccess(Future<SetSchemaResponse> future)
|
||||
throws Exception {
|
||||
SetSchemaResponse setSchemaResponse = future.get();
|
||||
assertWithMessage("SetSchemaResponse not successful.")
|
||||
.that(setSchemaResponse.isSuccess())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
public static List<GenericDocument> doGet(
|
||||
AppSearchSessionShim session, String namespace, String... uris) throws Exception {
|
||||
AppSearchBatchResult<String, GenericDocument> result =
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.appsearch.external.localstorage;
|
||||
|
||||
import static android.app.appsearch.AppSearchResult.RESULT_OK;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.expectThrows;
|
||||
@@ -25,6 +27,7 @@ import android.app.appsearch.GenericDocument;
|
||||
import android.app.appsearch.SearchResult;
|
||||
import android.app.appsearch.SearchResultPage;
|
||||
import android.app.appsearch.SearchSpec;
|
||||
import android.app.appsearch.SetSchemaResult;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.content.Context;
|
||||
import android.util.ArraySet;
|
||||
@@ -68,7 +71,7 @@ public class AppSearchImplTest {
|
||||
AppSearchImpl.create(
|
||||
mTemporaryFolder.newFolder(),
|
||||
context,
|
||||
/*userId=*/-1,
|
||||
VisibilityStore.NO_OP_USER_ID,
|
||||
/*globalQuerierPackage
|
||||
=*/ context.getPackageName());
|
||||
}
|
||||
@@ -745,6 +748,54 @@ public class AppSearchImplTest {
|
||||
.containsExactlyElementsIn(expectedTypes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSchema_incompatible() throws Exception {
|
||||
List<SchemaTypeConfigProto> existingSchemas =
|
||||
mAppSearchImpl.getSchemaProtoLocked().getTypesList();
|
||||
|
||||
List<AppSearchSchema> oldSchemas = new ArrayList<>();
|
||||
oldSchemas.add(
|
||||
new AppSearchSchema.Builder("Email")
|
||||
.addProperty(
|
||||
new AppSearchSchema.StringPropertyConfig.Builder("foo")
|
||||
.setCardinality(
|
||||
AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
|
||||
.setTokenizerType(
|
||||
AppSearchSchema.StringPropertyConfig
|
||||
.TOKENIZER_TYPE_PLAIN)
|
||||
.setIndexingType(
|
||||
AppSearchSchema.StringPropertyConfig
|
||||
.INDEXING_TYPE_PREFIXES)
|
||||
.build())
|
||||
.build());
|
||||
oldSchemas.add(new AppSearchSchema.Builder("Text").build());
|
||||
// Set schema Email to AppSearch database1
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database1",
|
||||
oldSchemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ false);
|
||||
|
||||
// Create incompatible schema
|
||||
List<AppSearchSchema> newSchemas =
|
||||
Collections.singletonList(new AppSearchSchema.Builder("Email").build());
|
||||
|
||||
// set email incompatible and delete text
|
||||
SetSchemaResult setSchemaResult =
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database1",
|
||||
newSchemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ true);
|
||||
assertThat(setSchemaResult.getDeletedSchemaTypes()).containsExactly("Text");
|
||||
assertThat(setSchemaResult.getIncompatibleSchemaTypes()).containsExactly("Email");
|
||||
assertThat(setSchemaResult.getResultCode()).isEqualTo(RESULT_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSchema() throws Exception {
|
||||
List<SchemaTypeConfigProto> existingSchemas =
|
||||
@@ -785,20 +836,17 @@ public class AppSearchImplTest {
|
||||
|
||||
final List<AppSearchSchema> finalSchemas =
|
||||
Collections.singletonList(new AppSearchSchema.Builder("Email").build());
|
||||
// Check the incompatible error has been thrown.
|
||||
AppSearchException e =
|
||||
expectThrows(
|
||||
AppSearchException.class,
|
||||
() ->
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database1",
|
||||
finalSchemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ false));
|
||||
assertThat(e).hasMessageThat().contains("Schema is incompatible");
|
||||
assertThat(e).hasMessageThat().contains("Deleted types: [package$database1/Document]");
|
||||
SetSchemaResult setSchemaResult =
|
||||
mAppSearchImpl.setSchema(
|
||||
"package",
|
||||
"database1",
|
||||
finalSchemas,
|
||||
/*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
|
||||
/*schemasPackageAccessible=*/ Collections.emptyMap(),
|
||||
/*forceOverride=*/ false);
|
||||
|
||||
// Check the Document type has been deleted.
|
||||
assertThat(setSchemaResult.getDeletedSchemaTypes()).containsExactly("Document");
|
||||
|
||||
// ForceOverride to delete.
|
||||
mAppSearchImpl.setSchema(
|
||||
|
||||
Reference in New Issue
Block a user