Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a309dd35 authored by Alexander Dorokhine's avatar Alexander Dorokhine Committed by Android (Google) Code Review
Browse files

Merge "Port the getDocuments() API to be synchronous."

parents 0e34fcd1 bc6fae14
Loading
Loading
Loading
Loading
+19 −7
Original line number Original line Diff line number Diff line
@@ -34,11 +34,11 @@ import java.util.Map;
 * @hide
 * @hide
 */
 */
public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
    @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mSuccesses;
    @NonNull private final Map<KeyType, ValueType> mSuccesses;
    @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures;
    @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures;


    private AppSearchBatchResult(
    private AppSearchBatchResult(
            @NonNull Map<KeyType, AppSearchResult<ValueType>> successes,
            @NonNull Map<KeyType, ValueType> successes,
            @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) {
            @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) {
        mSuccesses = successes;
        mSuccesses = successes;
        mFailures = failures;
        mFailures = failures;
@@ -61,13 +61,13 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
    }
    }


    /**
    /**
     * Returns a {@link Map} of all successful keys mapped to the successful
     * Returns a {@link Map} of all successful keys mapped to the successful {@link ValueType}
     * {@link AppSearchResult}s they produced.
     * values they produced.
     *
     *
     * <p>The values of the {@link Map} will not be {@code null}.
     * <p>The values of the {@link Map} will not be {@code null}.
     */
     */
    @NonNull
    @NonNull
    public Map<KeyType, AppSearchResult<ValueType>> getSuccesses() {
    public Map<KeyType, ValueType> getSuccesses() {
        return mSuccesses;
        return mSuccesses;
    }
    }


@@ -110,7 +110,7 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
     * @hide
     * @hide
     */
     */
    public static final class Builder<KeyType, ValueType> {
    public static final class Builder<KeyType, ValueType> {
        private final Map<KeyType, AppSearchResult<ValueType>> mSuccesses = new ArrayMap<>();
        private final Map<KeyType, ValueType> mSuccesses = new ArrayMap<>();
        private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
        private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();


        /** Creates a new {@link Builder} for this {@link AppSearchBatchResult}. */
        /** Creates a new {@link Builder} for this {@link AppSearchBatchResult}. */
@@ -125,6 +125,18 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
            return setResult(key, AppSearchResult.newSuccessfulResult(result));
            return setResult(key, AppSearchResult.newSuccessfulResult(result));
        }
        }


        /**
         * Associates the {@code key} with the given failure code and error message.
         *
         * <p>Any previous mapping for a key, whether success or failure, is deleted.
         */
        public Builder setFailure(
                @NonNull KeyType key,
                @AppSearchResult.ResultCode int resultCode,
                @Nullable String errorMessage) {
            return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage));
        }

        /**
        /**
         * Associates the {@code key} with the given {@code result}.
         * Associates the {@code key} with the given {@code result}.
         *
         *
@@ -133,7 +145,7 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
        @NonNull
        @NonNull
        public Builder setResult(@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) {
        public Builder setResult(@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) {
            if (result.isSuccess()) {
            if (result.isSuccess()) {
                mSuccesses.put(key, result);
                mSuccesses.put(key, result.getResultValue());
                mFailures.remove(key);
                mFailures.remove(key);
            } else {
            } else {
                mFailures.put(key, result);
                mFailures.put(key, result);
+52 −33
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ import com.google.android.icing.protobuf.InvalidProtocolBufferException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.BiConsumer;
@@ -193,44 +194,62 @@ public class AppSearchManager {
     * {@code AppSearch#getDocuments()} API provided by JetPack.
     * {@code AppSearch#getDocuments()} API provided by JetPack.
     *
     *
     * @param uris URIs of the documents to look up.
     * @param uris URIs of the documents to look up.
     * @param executor Executor on which to invoke the callback.
     * @return An {@link AppSearchBatchResult} mapping the document URIs to
     * @param callback Callback to receive the documents or error.
     *     {@link AppSearchDocument} values if they were successfully retrieved, a {@code null}
     *     failure if they were not found, or a {@link Throwable} failure describing the problem if
     *     an error occurred.
     */
     */
    public void getDocuments(
    public AppSearchBatchResult<String, AppSearchDocument> getDocuments(
            @NonNull List<String> uris,
            @NonNull List<String> uris) {
            @NonNull @CallbackExecutor Executor executor,
        // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending
            @NonNull BiConsumer<List<AppSearchDocument>, ? super Throwable> callback) {
        //     them in one big list.
        AndroidFuture<List<byte[]>> future = new AndroidFuture<>();
        AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
        future.whenCompleteAsync((documentProtos, err) -> {
        try {
            if (err != null) {
            mService.getDocuments(uris, future);
                callback.accept(null, err);
        } catch (RemoteException e) {
                return;
            future.completeExceptionally(e);
        }
        }
            if (documentProtos != null) {

                List<AppSearchDocument> results = new ArrayList<>(documentProtos.size());
        // Deserialize the protos into Document objects
                for (int i = 0; i < documentProtos.size(); i++) {
        AppSearchBatchResult<String, byte[]> protoResults = getFutureOrThrow(future);
        AppSearchBatchResult.Builder<String, AppSearchDocument> documentResultBuilder =
                new AppSearchBatchResult.Builder<>();

        // Translate successful results
        for (Map.Entry<String, byte[]> protoResult : protoResults.getSuccesses().entrySet()) {
            DocumentProto documentProto;
            DocumentProto documentProto;
            try {
            try {
                        documentProto = DocumentProto.parseFrom(documentProtos.get(i));
                documentProto = DocumentProto.parseFrom(protoResult.getValue());
            } catch (InvalidProtocolBufferException e) {
            } catch (InvalidProtocolBufferException e) {
                        callback.accept(null, e);
                documentResultBuilder.setFailure(
                        return;
                        protoResult.getKey(), AppSearchResult.RESULT_IO_ERROR, e.getMessage());
                continue;
            }
            }
                    results.add(new AppSearchDocument(documentProto));
            AppSearchDocument document;
            try {
                document = new AppSearchDocument(documentProto);
            } catch (Throwable t) {
                // These documents went through validation, so how could this fail? We must have
                // done something wrong.
                documentResultBuilder.setFailure(
                        protoResult.getKey(),
                        AppSearchResult.RESULT_INTERNAL_ERROR,
                        t.getMessage());
                continue;
            }
            }
                callback.accept(results, null);
            documentResultBuilder.setSuccess(protoResult.getKey(), document);
                return;
        }
        }
            // Nothing was supplied in the future at all

            callback.accept(null, new IllegalStateException(
        // Translate failed results
                    "Unknown failure occurred while retrieving documents"));
        for (Map.Entry<String, AppSearchResult<byte[]>> protoResult :
        }, executor);
                protoResults.getFailures().entrySet()) {
        // TODO(b/146386470) stream uris?
            documentResultBuilder.setFailure(
        try {
                    protoResult.getKey(),
            mService.getDocuments(uris.toArray(new String[uris.size()]), future);
                    protoResult.getValue().getResultCode(),
        } catch (RemoteException e) {
                    protoResult.getValue().getErrorMessage());
            future.completeExceptionally(e);
        }
        }

        return documentResultBuilder.build();
    }
    }


    /**
    /**
+0 −1
Original line number Original line Diff line number Diff line
@@ -56,7 +56,6 @@ public class AppSearchResult<ValueType> implements Parcelable {
    /**
    /**
     * An internal error occurred within AppSearch, which the caller cannot address.
     * An internal error occurred within AppSearch, which the caller cannot address.
     *
     *
     *
     * This error may be considered similar to {@link IllegalStateException}
     * This error may be considered similar to {@link IllegalStateException}
     */
     */
    public static final int RESULT_INTERNAL_ERROR = 2;
    public static final int RESULT_INTERNAL_ERROR = 2;
+7 −4
Original line number Original line Diff line number Diff line
@@ -51,11 +51,14 @@ interface IAppSearchManager {
     * Retrieves documents from the index.
     * Retrieves documents from the index.
     *
     *
     * @param uris The URIs of the documents to retrieve
     * @param uris The URIs of the documents to retrieve
     * @param callback {@link AndroidFuture}&lt;{@link List}&lt;byte[]&gt;&gt;. Will be completed
     * @param callback
     *     with a {@link List} containing serialized DocumentProtos, or completed exceptionally if
     *     {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link byte[]}&gt;&gt;.
     *     get fails.
     *     If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
     *     {@code callback} will be completed with an
     *     {@link AppSearchBatchResult}&lt;{@link String}, {@link byte[]}&gt;
     *     where the keys are document URIs, and the values are serialized Document protos.
     */
     */
    void getDocuments(in String[] uris, in AndroidFuture callback);
    void getDocuments(in List<String> uris, in AndroidFuture<AppSearchBatchResult> callback);


    /**
    /**
     * Searches a document based on a given specifications.
     * Searches a document based on a given specifications.
+18 −8
Original line number Original line Diff line number Diff line
@@ -37,7 +37,6 @@ import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.protobuf.InvalidProtocolBufferException;
import com.google.android.icing.protobuf.InvalidProtocolBufferException;


import java.io.IOException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.List;


/**
/**
@@ -112,7 +111,8 @@ public class AppSearchManagerService extends SystemService {
        }
        }


        @Override
        @Override
        public void getDocuments(String[] uris, AndroidFuture callback) {
        public void getDocuments(
                @NonNull List<String> uris, @NonNull AndroidFuture<AppSearchBatchResult> callback) {
            Preconditions.checkNotNull(uris);
            Preconditions.checkNotNull(uris);
            Preconditions.checkNotNull(callback);
            Preconditions.checkNotNull(callback);
            int callingUid = Binder.getCallingUidOrThrow();
            int callingUid = Binder.getCallingUidOrThrow();
@@ -120,13 +120,23 @@ public class AppSearchManagerService extends SystemService {
            long callingIdentity = Binder.clearCallingIdentity();
            long callingIdentity = Binder.clearCallingIdentity();
            try {
            try {
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                // Contains serialized DocumentProto. byte[][] is not transmissible via Binder.
                AppSearchBatchResult.Builder<String, byte[]> resultBuilder =
                List<byte[]> results = new ArrayList<>(uris.length);
                        new AppSearchBatchResult.Builder<>();
                for (String uri : uris) {
                for (int i = 0; i < uris.size(); i++) {
                    DocumentProto result = impl.getDocument(callingUid, uri);
                    String uri = uris.get(i);
                    results.add(result.toByteArray());
                    try {
                        DocumentProto document = impl.getDocument(callingUid, uri);
                        if (document == null) {
                            resultBuilder.setFailure(
                                    uri, AppSearchResult.RESULT_NOT_FOUND, /*errorMessage=*/ null);
                        } else {
                            resultBuilder.setSuccess(uri, document.toByteArray());
                        }
                        }
                callback.complete(results);
                    } catch (Throwable t) {
                        resultBuilder.setResult(uri, throwableToFailedResult(t));
                    }
                }
                callback.complete(resultBuilder.build());
            } catch (Throwable t) {
            } catch (Throwable t) {
                callback.completeExceptionally(t);
                callback.completeExceptionally(t);
            } finally {
            } finally {