Porting the async AppSearchSession to platform.
AppSearchSession has different context in platform, it's not directly ported from jetpack. This change switch AppSearch in platform from synchronize to async. AppSearch platform Async design doc: https://docs.google.com/document/d/1YGrM4s65ZhWy0P1zdI1ssfjWuCctOKxdxUKzUYS5MyY/edit?usp=sharing Changes included: #89b527b: Replace AppSearchManager with a SearchSession. Bug: 162450968 Test: presubmit Change-Id: I4c7e1b618b6f8eab2087813c32d15339b3daa8ab
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright 2020, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.app.appsearch;
|
||||
|
||||
/** {@hide} */
|
||||
parcelable AppSearchBatchResult;
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package android.app.appsearch;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelableException;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
@@ -27,7 +29,10 @@ import com.android.internal.util.Preconditions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class provides access to the centralized AppSearch index maintained by the system.
|
||||
@@ -40,12 +45,99 @@ import java.util.concurrent.ExecutionException;
|
||||
// TODO(b/148046169): This class header needs a detailed example/tutorial.
|
||||
@SystemService(Context.APP_SEARCH_SERVICE)
|
||||
public class AppSearchManager {
|
||||
private static final String DEFAULT_DATABASE = "";
|
||||
/**
|
||||
* The default empty database name.
|
||||
* @hide
|
||||
*/
|
||||
public static final String DEFAULT_DATABASE_NAME = "";
|
||||
|
||||
private final IAppSearchManager mService;
|
||||
|
||||
/** @hide */
|
||||
public AppSearchManager(@NonNull IAppSearchManager service) {
|
||||
mService = service;
|
||||
mService = Objects.requireNonNull(service);
|
||||
}
|
||||
|
||||
/** Contains information about how to create the search session. */
|
||||
public static final class SearchContext {
|
||||
final String mDatabaseName;
|
||||
|
||||
SearchContext(@NonNull String databaseName) {
|
||||
mDatabaseName = Objects.requireNonNull(databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the database to create or open.
|
||||
*
|
||||
* <p>Databases with different names are fully separate with distinct types, namespaces,
|
||||
* and data.
|
||||
*/
|
||||
@NonNull
|
||||
public String getDatabaseName() {
|
||||
return mDatabaseName;
|
||||
}
|
||||
|
||||
/** Builder for {@link SearchContext} objects. */
|
||||
public static final class Builder {
|
||||
private String mDatabaseName = DEFAULT_DATABASE_NAME;
|
||||
private boolean mBuilt = false;
|
||||
|
||||
/**
|
||||
* Sets the name of the database associated with {@link AppSearchSession}.
|
||||
*
|
||||
* <p>{@link AppSearchSession} will create or open a database under the given name.
|
||||
*
|
||||
* <p>Databases with different names are fully separate with distinct types, namespaces,
|
||||
* and data.
|
||||
*
|
||||
* <p>Database name cannot contain {@code '/'}.
|
||||
*
|
||||
* <p>If not specified, defaults to {@link #DEFAULT_DATABASE_NAME}.
|
||||
* @param databaseName The name of the database.
|
||||
* @throws IllegalArgumentException if the databaseName contains {@code '/'}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDatabaseName(@NonNull String databaseName) {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
Objects.requireNonNull(databaseName);
|
||||
if (databaseName.contains("/")) {
|
||||
throw new IllegalArgumentException("Database name cannot contain '/'");
|
||||
}
|
||||
mDatabaseName = databaseName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a {@link SearchContext} instance. */
|
||||
@NonNull
|
||||
public SearchContext build() {
|
||||
Preconditions.checkState(!mBuilt, "Builder has already been used");
|
||||
mBuilt = true;
|
||||
return new SearchContext(mDatabaseName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AppSearchSession}.
|
||||
*
|
||||
* <p>This process requires an AppSearch native indexing file system for each user. If it's not
|
||||
* created for this user, the initialization process will create one under user's directory.
|
||||
*
|
||||
* @param searchContext The {@link SearchContext} contains all information to create a new
|
||||
* {@link AppSearchSession}
|
||||
* @param executor Executor on which to invoke the callback.
|
||||
* @param callback The {@link AppSearchResult}<{@link AppSearchSession}> of
|
||||
* performing this operation. Or a {@link AppSearchResult} with failure
|
||||
* reason code and error information.
|
||||
*/
|
||||
public void createSearchSession(
|
||||
@NonNull SearchContext searchContext,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
|
||||
Objects.requireNonNull(searchContext);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
AppSearchSession.createSearchSession(searchContext, mService, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +191,7 @@ public class AppSearchManager {
|
||||
*
|
||||
* @param request The schema update request.
|
||||
* @return the result of performing this operation.
|
||||
*
|
||||
* @deprecated use {@link AppSearchSession#setSchema} instead.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@@ -113,9 +205,14 @@ public class AppSearchManager {
|
||||
}
|
||||
AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
|
||||
try {
|
||||
mService.setSchema(DEFAULT_DATABASE, schemaBundles, request.isForceOverride(), future);
|
||||
mService.setSchema(DEFAULT_DATABASE_NAME, schemaBundles, request.isForceOverride(),
|
||||
new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
future.complete(result);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
future.completeExceptionally(e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
return getFutureOrThrow(future);
|
||||
}
|
||||
@@ -134,6 +231,9 @@ public class AppSearchManager {
|
||||
* {@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.
|
||||
* @throws RuntimeException If an error occurred during the execution.
|
||||
*
|
||||
* @deprecated use {@link AppSearchSession#putDocuments} instead.
|
||||
* @hide
|
||||
*/
|
||||
public AppSearchBatchResult<String, Void> putDocuments(@NonNull PutDocumentsRequest request) {
|
||||
@@ -146,7 +246,16 @@ public class AppSearchManager {
|
||||
}
|
||||
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
|
||||
try {
|
||||
mService.putDocuments(DEFAULT_DATABASE, documentBundles, future);
|
||||
mService.putDocuments(DEFAULT_DATABASE_NAME, documentBundles,
|
||||
new IAppSearchBatchResultCallback.Stub() {
|
||||
public void onResult(AppSearchBatchResult result) {
|
||||
future.complete(result);
|
||||
}
|
||||
|
||||
public void onSystemError(ParcelableException exception) {
|
||||
future.completeExceptionally(exception);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
@@ -165,6 +274,9 @@ public class AppSearchManager {
|
||||
* {@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}.
|
||||
* @throws RuntimeException If an error occurred during the execution.
|
||||
*
|
||||
* @deprecated use {@link AppSearchSession#getByUri} instead.
|
||||
*/
|
||||
public AppSearchBatchResult<String, GenericDocument> getByUri(
|
||||
@NonNull GetByUriRequest request) {
|
||||
@@ -173,7 +285,16 @@ public class AppSearchManager {
|
||||
List<String> uris = new ArrayList<>(request.getUris());
|
||||
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
|
||||
try {
|
||||
mService.getDocuments(DEFAULT_DATABASE, request.getNamespace(), uris, future);
|
||||
mService.getDocuments(DEFAULT_DATABASE_NAME, request.getNamespace(), uris,
|
||||
new IAppSearchBatchResultCallback.Stub() {
|
||||
public void onResult(AppSearchBatchResult result) {
|
||||
future.complete(result);
|
||||
}
|
||||
|
||||
public void onSystemError(ParcelableException exception) {
|
||||
future.completeExceptionally(exception);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
@@ -252,6 +373,9 @@ public class AppSearchManager {
|
||||
*
|
||||
* @param queryExpression Query String to search.
|
||||
* @param searchSpec Spec for setting filters, raw query etc.
|
||||
* @throws RuntimeException If an error occurred during the execution.
|
||||
*
|
||||
* @deprecated use AppSearchSession#query instead.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@@ -261,7 +385,7 @@ public class AppSearchManager {
|
||||
// them in one big list.
|
||||
AndroidFuture<AppSearchResult> searchResultsFuture = new AndroidFuture<>();
|
||||
try {
|
||||
mService.query(DEFAULT_DATABASE, queryExpression,
|
||||
mService.query(DEFAULT_DATABASE_NAME, queryExpression,
|
||||
searchSpec.getBundle(), searchResultsFuture);
|
||||
} catch (RemoteException e) {
|
||||
searchResultsFuture.completeExceptionally(e);
|
||||
@@ -278,7 +402,7 @@ public class AppSearchManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes {@link GenericDocument}s by URI.
|
||||
* Removes {@link GenericDocument}s by URI.
|
||||
*
|
||||
* <p>You should not call this method directly; instead, use the {@code AppSearch#delete()} API
|
||||
* provided by JetPack.
|
||||
@@ -289,12 +413,24 @@ public class AppSearchManager {
|
||||
* 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}.
|
||||
* @throws RuntimeException If an error occurred during the execution.
|
||||
*
|
||||
* @deprecated use {@link AppSearchSession#removeByUri} instead.
|
||||
*/
|
||||
public AppSearchBatchResult<String, Void> removeByUri(@NonNull RemoveByUriRequest request) {
|
||||
List<String> uris = new ArrayList<>(request.getUris());
|
||||
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
|
||||
try {
|
||||
mService.removeByUri(DEFAULT_DATABASE, request.getNamespace(), uris, future);
|
||||
mService.removeByUri(DEFAULT_DATABASE_NAME, request.getNamespace(), uris,
|
||||
new IAppSearchBatchResultCallback.Stub() {
|
||||
public void onResult(AppSearchBatchResult result) {
|
||||
future.complete(result);
|
||||
}
|
||||
|
||||
public void onSystemError(ParcelableException exception) {
|
||||
future.completeExceptionally(exception);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright 2020, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.app.appsearch;
|
||||
|
||||
/** {@hide} */
|
||||
parcelable AppSearchResult;
|
||||
@@ -19,9 +19,11 @@ package android.app.appsearch;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
@@ -218,4 +220,25 @@ public final class AppSearchResult<ValueType> implements Parcelable {
|
||||
@ResultCode int resultCode, @Nullable String errorMessage) {
|
||||
return new AppSearchResult<>(resultCode, /*resultValue=*/ null, errorMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@NonNull
|
||||
public static <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
|
||||
@NonNull Throwable t) {
|
||||
if (t instanceof AppSearchException) {
|
||||
return ((AppSearchException) t).toAppSearchResult();
|
||||
}
|
||||
|
||||
@AppSearchResult.ResultCode int resultCode;
|
||||
if (t instanceof IllegalStateException) {
|
||||
resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
|
||||
} else if (t instanceof IllegalArgumentException) {
|
||||
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
|
||||
} else if (t instanceof IOException) {
|
||||
resultCode = AppSearchResult.RESULT_IO_ERROR;
|
||||
} else {
|
||||
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
|
||||
}
|
||||
return AppSearchResult.newFailedResult(resultCode, t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.appsearch;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelableException;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Represents a connection to an AppSearch storage system where {@link GenericDocument}s can be
|
||||
* placed and queried.
|
||||
* @hide
|
||||
*/
|
||||
public final class AppSearchSession {
|
||||
private final String mDatabaseName;
|
||||
private final IAppSearchManager mService;
|
||||
|
||||
static void createSearchSession(
|
||||
@NonNull AppSearchManager.SearchContext searchContext,
|
||||
@NonNull IAppSearchManager service,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
|
||||
AppSearchSession searchSession =
|
||||
new AppSearchSession(searchContext.mDatabaseName, service);
|
||||
searchSession.initialize(executor, callback);
|
||||
}
|
||||
|
||||
// NOTE: No instance of this class should be created or returned except via initialize().
|
||||
// Once the callback.accept has been called here, the class is ready to use.
|
||||
private void initialize(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
|
||||
try {
|
||||
mService.initialize(new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
executor.execute(() -> {
|
||||
if (result.isSuccess()) {
|
||||
callback.accept(
|
||||
AppSearchResult.newSuccessfulResult(AppSearchSession.this));
|
||||
} else {
|
||||
callback.accept(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private AppSearchSession(@NonNull String databaseName, @NonNull IAppSearchManager service) {
|
||||
mDatabaseName = databaseName;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the schema will be used by documents provided to the {@link #putDocuments} method.
|
||||
*
|
||||
* <p>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:
|
||||
* <ul>
|
||||
* <li>Addition of new types
|
||||
* <li>Addition of new
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} or
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} properties to a
|
||||
* type
|
||||
* <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED REPEATED} property.
|
||||
* </ul>
|
||||
*
|
||||
* <p>The following types of schema changes are not backwards-compatible:
|
||||
* <ul>
|
||||
* <li>Removal of an existing type
|
||||
* <li>Removal of a property from a type
|
||||
* <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property
|
||||
* <li>For properties of {@code Document} type, changing the schema type of
|
||||
* {@code Document}s of that property
|
||||
* <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL OPTIONAL} property into a
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property).
|
||||
* <li>Adding a
|
||||
* {@link AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED REQUIRED} property.
|
||||
* </ul>
|
||||
* <p>Supplying a schema with such changes will, by default, result in this call returning an
|
||||
* {@link AppSearchResult} with a code of {@link AppSearchResult#RESULT_INVALID_SCHEMA} and an
|
||||
* error 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 returning an {@link AppSearchResult} with the
|
||||
* {@link AppSearchResult#RESULT_INVALID_SCHEMA} error code, all documents which are not
|
||||
* compatible with the new schema will be deleted and the incompatible schema will be applied.
|
||||
*
|
||||
* <p>It is a no-op to set the same schema as has been previously set; this is handled
|
||||
* efficiently.
|
||||
*
|
||||
* @param request The schema update request.
|
||||
* @param executor Executor on which to invoke the callback.
|
||||
* @param callback Callback to receive errors resulting from setting the schema. If the
|
||||
* operation succeeds, the callback will be invoked with {@code null}.
|
||||
*/
|
||||
public void setSchema(
|
||||
@NonNull SetSchemaRequest request,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<Void>> callback) {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size());
|
||||
for (AppSearchSchema schema : request.getSchemas()) {
|
||||
schemaBundles.add(schema.getBundle());
|
||||
}
|
||||
try {
|
||||
mService.setSchema(mDatabaseName, schemaBundles, request.isForceOverride(),
|
||||
new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
executor.execute(() -> callback.accept(result));
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes documents into AppSearch.
|
||||
*
|
||||
* <p>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
|
||||
* @param executor Executor on which to invoke the callback.
|
||||
* @param callback Callback to receive 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.
|
||||
* Or {@link BatchResultCallback#onSystemError} will be invoked with an
|
||||
* {@link AppSearchException} if an error occurred in AppSearch initialization
|
||||
* or a cause {@link Throwable} if other error occurred in AppSearch service.
|
||||
*/
|
||||
public void putDocuments(
|
||||
@NonNull PutDocumentsRequest request,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BatchResultCallback<String, Void> callback) {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
List<GenericDocument> documents = request.getDocuments();
|
||||
List<Bundle> documentBundles = new ArrayList<>(documents.size());
|
||||
for (int i = 0; i < documents.size(); i++) {
|
||||
documentBundles.add(documents.get(i).getBundle());
|
||||
}
|
||||
try {
|
||||
mService.putDocuments(mDatabaseName, documentBundles,
|
||||
new IAppSearchBatchResultCallback.Stub() {
|
||||
public void onResult(AppSearchBatchResult result) {
|
||||
executor.execute(() -> callback.onResult(result));
|
||||
}
|
||||
|
||||
public void onSystemError(ParcelableException exception) {
|
||||
executor.execute(() -> callback.onSystemError(exception.getCause()));
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves {@link GenericDocument}s by URI.
|
||||
*
|
||||
* @param request {@link GetByUriRequest} containing URIs to be retrieved.
|
||||
* @param executor Executor on which to invoke the callback.
|
||||
* @param callback Callback to receive 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}.
|
||||
* Or {@link BatchResultCallback#onSystemError} will be invoked with an
|
||||
* {@link AppSearchException} if an error occurred in AppSearch initialization
|
||||
* or a cause {@link Throwable} if other error occurred in AppSearch service.
|
||||
*/
|
||||
public void getByUri(
|
||||
@NonNull GetByUriRequest request,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BatchResultCallback<String, GenericDocument> callback) {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
try {
|
||||
mService.getDocuments(mDatabaseName, request.getNamespace(),
|
||||
new ArrayList<>(request.getUris()),
|
||||
new IAppSearchBatchResultCallback.Stub() {
|
||||
public void onResult(AppSearchBatchResult result) {
|
||||
executor.execute(() -> {
|
||||
AppSearchBatchResult.Builder<String, GenericDocument>
|
||||
documentResultBuilder =
|
||||
new AppSearchBatchResult.Builder<>();
|
||||
|
||||
// Translate successful results
|
||||
for (Map.Entry<String, Bundle> bundleEntry :
|
||||
(Set<Map.Entry<String, Bundle>>)
|
||||
result.getSuccesses().entrySet()) {
|
||||
GenericDocument document;
|
||||
try {
|
||||
document = new GenericDocument(bundleEntry.getValue());
|
||||
} catch (Throwable t) {
|
||||
// These documents went through validation, so how could
|
||||
// this fail? We must have done something wrong.
|
||||
documentResultBuilder.setFailure(
|
||||
bundleEntry.getKey(),
|
||||
AppSearchResult.RESULT_INTERNAL_ERROR,
|
||||
t.getMessage());
|
||||
continue;
|
||||
}
|
||||
documentResultBuilder.setSuccess(
|
||||
bundleEntry.getKey(), document);
|
||||
}
|
||||
|
||||
// Translate failed results
|
||||
for (Map.Entry<String, AppSearchResult<Bundle>> bundleEntry :
|
||||
(Set<Map.Entry<String, AppSearchResult<Bundle>>>)
|
||||
result.getFailures().entrySet()) {
|
||||
documentResultBuilder.setFailure(
|
||||
bundleEntry.getKey(),
|
||||
bundleEntry.getValue().getResultCode(),
|
||||
bundleEntry.getValue().getErrorMessage());
|
||||
}
|
||||
callback.onResult(documentResultBuilder.build());
|
||||
});
|
||||
}
|
||||
|
||||
public void onSystemError(ParcelableException exception) {
|
||||
executor.execute(() -> callback.onSystemError(exception.getCause()));
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes {@link GenericDocument}s from the index by URI.
|
||||
*
|
||||
* @param request Request containing URIs to be removed.
|
||||
* @param executor Executor on which to invoke the callback.
|
||||
* @param callback Callback to receive 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}.
|
||||
* Or {@link BatchResultCallback#onSystemError} will be invoked with an
|
||||
* {@link AppSearchException} if an error occurred in AppSearch initialization
|
||||
* or a cause {@link Throwable} if other error occurred in AppSearch service.
|
||||
*/
|
||||
public void removeByUri(
|
||||
@NonNull RemoveByUriRequest request,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull BatchResultCallback<String, Void> callback) {
|
||||
Objects.requireNonNull(request);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
try {
|
||||
mService.removeByUri(mDatabaseName, request.getNamespace(),
|
||||
new ArrayList<>(request.getUris()),
|
||||
new IAppSearchBatchResultCallback.Stub() {
|
||||
public void onResult(AppSearchBatchResult result) {
|
||||
executor.execute(() -> callback.onResult(result));
|
||||
}
|
||||
|
||||
public void onSystemError(ParcelableException exception) {
|
||||
executor.execute(() -> callback.onSystemError(exception.getCause()));
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/162450968) port query() and SearchResults.java to platform.
|
||||
// TODO(b/162450968) port removeByQuery() to platform.
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The callback interface to return {@link AppSearchBatchResult}.
|
||||
*
|
||||
* @param <KeyType> The type of the keys for {@link AppSearchBatchResult#getSuccesses} and
|
||||
* {@link AppSearchBatchResult#getFailures}.
|
||||
* @param <ValueType> The type of result objects associated with the keys.
|
||||
* @hide
|
||||
*/
|
||||
public interface BatchResultCallback<KeyType, ValueType> {
|
||||
|
||||
/**
|
||||
* Called when {@link AppSearchBatchResult} results are ready.
|
||||
*
|
||||
* @param result The result of the executed request.
|
||||
*/
|
||||
void onResult(AppSearchBatchResult<KeyType, ValueType> result);
|
||||
|
||||
|
||||
/**
|
||||
* Called when a system error occurred.
|
||||
*
|
||||
* @param throwable The cause throwable.
|
||||
*/
|
||||
default void onSystemError(Throwable throwable) {
|
||||
if (throwable != null) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright 2020, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.app.appsearch;
|
||||
|
||||
import android.app.appsearch.AppSearchBatchResult;
|
||||
import android.os.ParcelableException;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface IAppSearchBatchResultCallback {
|
||||
void onResult(in AppSearchBatchResult result);
|
||||
void onSystemError(in ParcelableException exception);
|
||||
}
|
||||
@@ -17,10 +17,12 @@ package android.app.appsearch;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.app.appsearch.AppSearchBatchResult;
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
import android.app.appsearch.IAppSearchBatchResultCallback;
|
||||
import android.app.appsearch.IAppSearchResultCallback;
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
|
||||
parcelable AppSearchResult;
|
||||
parcelable AppSearchBatchResult;
|
||||
parcelable SearchResults;
|
||||
|
||||
/** {@hide} */
|
||||
@@ -32,14 +34,14 @@ interface IAppSearchManager {
|
||||
* @param schemaBundles List of AppSearchSchema bundles.
|
||||
* @param forceOverride Whether to apply the new schema even if it is incompatible. All
|
||||
* incompatible documents will be deleted.
|
||||
* @param callback {@link AndroidFuture}<{@link AppSearchResult}<{@link Void}>>.
|
||||
* The results of the call.
|
||||
* @param callback {@link IAppSearchResultCallback#onResult} will be called with an
|
||||
* {@link AppSearchResult}<{@link Void}>.
|
||||
*/
|
||||
void setSchema(
|
||||
in String databaseName,
|
||||
in List<Bundle> schemaBundles,
|
||||
boolean forceOverride,
|
||||
in AndroidFuture<AppSearchResult> callback);
|
||||
in IAppSearchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Inserts documents into the index.
|
||||
@@ -47,16 +49,16 @@ interface IAppSearchManager {
|
||||
* @param databaseName The name of the database where this document lives.
|
||||
* @param documentBundes List of GenericDocument bundles.
|
||||
* @param callback
|
||||
* {@link AndroidFuture}<{@link AppSearchBatchResult}<{@link String}, {@link Void}>>.
|
||||
* If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
|
||||
* {@code callback} will be completed with an
|
||||
* If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
|
||||
* will be called with the cause throwable. Otherwise,
|
||||
* {@link IAppSearchBatchResultCallback#onResult} will be called with an
|
||||
* {@link AppSearchBatchResult}<{@link String}, {@link Void}>
|
||||
* where the keys are document URIs, and the values are {@code null}.
|
||||
*/
|
||||
void putDocuments(
|
||||
in String databaseName,
|
||||
in List<Bundle> documentBundles,
|
||||
in AndroidFuture<AppSearchBatchResult> callback);
|
||||
in IAppSearchBatchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Retrieves documents from the index.
|
||||
@@ -65,9 +67,9 @@ interface IAppSearchManager {
|
||||
* @param namespace The namespace this document resides in.
|
||||
* @param uris The URIs of the documents to retrieve
|
||||
* @param callback
|
||||
* {@link AndroidFuture}<{@link AppSearchBatchResult}<{@link String}, {@link Bundle}>>.
|
||||
* If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
|
||||
* {@code callback} will be completed with an
|
||||
* If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
|
||||
* will be called with the cause throwable. Otherwise,
|
||||
* {@link IAppSearchBatchResultCallback#onResult} will be called with an
|
||||
* {@link AppSearchBatchResult}<{@link String}, {@link Bundle}>
|
||||
* where the keys are document URIs, and the values are Document bundles.
|
||||
*/
|
||||
@@ -75,7 +77,7 @@ interface IAppSearchManager {
|
||||
in String databaseName,
|
||||
in String namespace,
|
||||
in List<String> uris,
|
||||
in AndroidFuture<AppSearchBatchResult> callback);
|
||||
in IAppSearchBatchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Searches a document based on a given specifications.
|
||||
@@ -98,9 +100,9 @@ interface IAppSearchManager {
|
||||
* @param namespace Namespace of the document to remove.
|
||||
* @param uris The URIs of the documents to delete
|
||||
* @param callback
|
||||
* {@link AndroidFuture}<{@link AppSearchBatchResult}<{@link String}, {@link Void}>>.
|
||||
* If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
|
||||
* {@code callback} will be completed with an
|
||||
* If the call fails to start, {@link IAppSearchBatchResultCallback#onSystemError}
|
||||
* will be called with the cause throwable. Otherwise,
|
||||
* {@link IAppSearchBatchResultCallback#onResult} will be called with an
|
||||
* {@link AppSearchBatchResult}<{@link String}, {@link Void}>
|
||||
* where the keys are document URIs. If a document doesn't exist, it will be reported as a
|
||||
* failure where the {@code throwable} is {@code null}.
|
||||
@@ -109,7 +111,7 @@ interface IAppSearchManager {
|
||||
in String databaseName,
|
||||
in String namespace,
|
||||
in List<String> uris,
|
||||
in AndroidFuture<AppSearchBatchResult> callback);
|
||||
in IAppSearchBatchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Removes documents by given query.
|
||||
@@ -124,4 +126,12 @@ interface IAppSearchManager {
|
||||
in String queryExpression,
|
||||
in Bundle searchSpecBundle,
|
||||
in AndroidFuture<AppSearchResult> callback);
|
||||
|
||||
/**
|
||||
* Creates and initializes AppSearchImpl for the calling app.
|
||||
*
|
||||
* @param callback {@link IAppSearchResultCallback#onResult} will be called with an
|
||||
* {@link AppSearchResult}<{@link Void}>.
|
||||
*/
|
||||
void initialize(in IAppSearchResultCallback callback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright 2020, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.app.appsearch;
|
||||
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
import android.os.ParcelableException;
|
||||
|
||||
/** {@hide} */
|
||||
oneway interface IAppSearchResultCallback {
|
||||
void onResult(in AppSearchResult result);
|
||||
}
|
||||
@@ -15,27 +15,32 @@
|
||||
*/
|
||||
package com.android.server.appsearch;
|
||||
|
||||
import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.appsearch.AppSearchBatchResult;
|
||||
import android.app.appsearch.AppSearchResult;
|
||||
import android.app.appsearch.AppSearchSchema;
|
||||
import android.app.appsearch.GenericDocument;
|
||||
import android.app.appsearch.IAppSearchBatchResultCallback;
|
||||
import android.app.appsearch.IAppSearchManager;
|
||||
import android.app.appsearch.IAppSearchResultCallback;
|
||||
import android.app.appsearch.SearchResultPage;
|
||||
import android.app.appsearch.SearchSpec;
|
||||
import android.app.appsearch.exceptions.AppSearchException;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelableException;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -61,10 +66,9 @@ public class AppSearchManagerService extends SystemService {
|
||||
@NonNull String databaseName,
|
||||
@NonNull List<Bundle> schemaBundles,
|
||||
boolean forceOverride,
|
||||
@NonNull AndroidFuture<AppSearchResult> callback) {
|
||||
@NonNull IAppSearchResultCallback callback) {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(schemaBundles);
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
@@ -76,9 +80,10 @@ public class AppSearchManagerService extends SystemService {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
|
||||
impl.setSchema(databaseName, schemas, forceOverride);
|
||||
callback.complete(AppSearchResult.newSuccessfulResult(/*result=*/ null));
|
||||
invokeCallbackOnResult(callback,
|
||||
AppSearchResult.newSuccessfulResult(/*result=*/ null));
|
||||
} catch (Throwable t) {
|
||||
callback.complete(throwableToFailedResult(t));
|
||||
invokeCallbackOnError(callback, t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
@@ -88,7 +93,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
public void putDocuments(
|
||||
@NonNull String databaseName,
|
||||
@NonNull List<Bundle> documentBundles,
|
||||
@NonNull AndroidFuture<AppSearchBatchResult> callback) {
|
||||
@NonNull IAppSearchBatchResultCallback callback) {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(documentBundles);
|
||||
Preconditions.checkNotNull(callback);
|
||||
@@ -96,22 +101,24 @@ public class AppSearchManagerService extends SystemService {
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
|
||||
AppSearchBatchResult.Builder<String, Void> resultBuilder =
|
||||
new AppSearchBatchResult.Builder<>();
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
|
||||
for (int i = 0; i < documentBundles.size(); i++) {
|
||||
GenericDocument document = new GenericDocument(documentBundles.get(i));
|
||||
try {
|
||||
// TODO(b/173451571): reduce burden of binder thread by enqueue request onto
|
||||
// a separate thread.
|
||||
impl.putDocument(databaseName, document);
|
||||
resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
|
||||
} catch (Throwable t) {
|
||||
resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
|
||||
}
|
||||
}
|
||||
callback.complete(resultBuilder.build());
|
||||
invokeCallbackOnResult(callback, resultBuilder.build());
|
||||
} catch (Throwable t) {
|
||||
callback.completeExceptionally(t);
|
||||
invokeCallbackOnError(callback, t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
@@ -119,7 +126,8 @@ public class AppSearchManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void getDocuments(@NonNull String databaseName, @NonNull String namespace,
|
||||
@NonNull List<String> uris, @NonNull AndroidFuture<AppSearchBatchResult> callback) {
|
||||
@NonNull List<String> uris,
|
||||
@NonNull IAppSearchBatchResultCallback callback) {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(namespace);
|
||||
Preconditions.checkNotNull(uris);
|
||||
@@ -128,10 +136,10 @@ public class AppSearchManagerService extends SystemService {
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
|
||||
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
|
||||
new AppSearchBatchResult.Builder<>();
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
|
||||
for (int i = 0; i < uris.size(); i++) {
|
||||
String uri = uris.get(i);
|
||||
try {
|
||||
@@ -141,9 +149,9 @@ public class AppSearchManagerService extends SystemService {
|
||||
resultBuilder.setResult(uri, throwableToFailedResult(t));
|
||||
}
|
||||
}
|
||||
callback.complete(resultBuilder.build());
|
||||
invokeCallbackOnResult(callback, resultBuilder.build());
|
||||
} catch (Throwable t) {
|
||||
callback.completeExceptionally(t);
|
||||
invokeCallbackOnError(callback, t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
@@ -182,19 +190,19 @@ public class AppSearchManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void removeByUri(@NonNull String databaseName, @NonNull String namespace,
|
||||
List<String> uris, AndroidFuture<AppSearchBatchResult> callback) {
|
||||
@NonNull List<String> uris,
|
||||
@NonNull IAppSearchBatchResultCallback callback) {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(namespace);
|
||||
Preconditions.checkNotNull(uris);
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
AppSearchBatchResult.Builder<String, Void> resultBuilder =
|
||||
new AppSearchBatchResult.Builder<>();
|
||||
try {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
|
||||
AppSearchBatchResult.Builder<String, Void> resultBuilder =
|
||||
new AppSearchBatchResult.Builder<>();
|
||||
for (int i = 0; i < uris.size(); i++) {
|
||||
String uri = uris.get(i);
|
||||
try {
|
||||
@@ -204,9 +212,9 @@ public class AppSearchManagerService extends SystemService {
|
||||
resultBuilder.setResult(uri, throwableToFailedResult(t));
|
||||
}
|
||||
}
|
||||
callback.complete(resultBuilder.build());
|
||||
invokeCallbackOnResult(callback, resultBuilder.build());
|
||||
} catch (Throwable t) {
|
||||
callback.completeExceptionally(t);
|
||||
invokeCallbackOnError(callback, t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
@@ -237,6 +245,21 @@ public class AppSearchManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(@NonNull IAppSearchResultCallback callback) {
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
|
||||
} catch (Throwable t) {
|
||||
invokeCallbackOnError(callback, t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites the database name by adding a prefix of unique name for the given uid.
|
||||
*
|
||||
@@ -256,23 +279,51 @@ public class AppSearchManagerService extends SystemService {
|
||||
return callingUidName + CALLING_NAME_DATABASE_DELIMITER + databaseName;
|
||||
}
|
||||
|
||||
private <ValueType> AppSearchResult<ValueType> throwableToFailedResult(
|
||||
@NonNull Throwable t) {
|
||||
if (t instanceof AppSearchException) {
|
||||
return ((AppSearchException) t).toAppSearchResult();
|
||||
/** Invokes the {@link IAppSearchResultCallback} with the result. */
|
||||
private void invokeCallbackOnResult(IAppSearchResultCallback callback,
|
||||
AppSearchResult result) {
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send result to the callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
@AppSearchResult.ResultCode int resultCode;
|
||||
if (t instanceof IllegalStateException) {
|
||||
resultCode = AppSearchResult.RESULT_INTERNAL_ERROR;
|
||||
} else if (t instanceof IllegalArgumentException) {
|
||||
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
|
||||
} else if (t instanceof IOException) {
|
||||
resultCode = AppSearchResult.RESULT_IO_ERROR;
|
||||
} else {
|
||||
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
|
||||
/** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
|
||||
private void invokeCallbackOnResult(IAppSearchBatchResultCallback callback,
|
||||
AppSearchBatchResult result) {
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send result to the callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the {@link IAppSearchResultCallback} with an throwable.
|
||||
*
|
||||
* <p>The throwable is convert to a {@link AppSearchResult};
|
||||
*/
|
||||
private void invokeCallbackOnError(IAppSearchResultCallback callback, Throwable throwable) {
|
||||
try {
|
||||
callback.onResult(throwableToFailedResult(throwable));
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send result to the callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the {@link IAppSearchBatchResultCallback} with an throwable.
|
||||
*
|
||||
* <p>The throwable is converted to {@link ParcelableException}.
|
||||
*/
|
||||
private void invokeCallbackOnError(IAppSearchBatchResultCallback callback,
|
||||
Throwable throwable) {
|
||||
try {
|
||||
callback.onSystemError(new ParcelableException(throwable));
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Unable to send error to the callback", e);
|
||||
}
|
||||
return AppSearchResult.newFailedResult(resultCode, t.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user