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

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

Merge "Implement putDocuments() support in AppSearchImpl."

parents 4a9cddd4 0c457e57
Loading
Loading
Loading
Loading
+60 −15
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.AppSearchSchema.PropertyConfig;
import android.os.Bundle;
import android.util.Log;

@@ -574,10 +575,6 @@ public final class AppSearch {
     * @hide
     */
    public static class Email extends Document {

        /** The name of the schema type for {@link Email} documents.*/
        public static final String SCHEMA_TYPE = "builtin:Email";

        private static final String KEY_FROM = "from";
        private static final String KEY_TO = "to";
        private static final String KEY_CC = "cc";
@@ -585,14 +582,53 @@ public final class AppSearch {
        private static final String KEY_SUBJECT = "subject";
        private static final String KEY_BODY = "body";

        /**
         * Creates a new {@link Email} from the contents of an existing {@link Document}.
         *
         * @param document The {@link Document} containing the email content.
         */
        public Email(@NonNull Document document) {
            super(document);
        }
        /** The name of the schema type for {@link Email} documents.*/
        public static final String SCHEMA_TYPE = "builtin:Email";

        public static final AppSearchSchema SCHEMA = AppSearchSchema.newBuilder(SCHEMA_TYPE)
                .addProperty(AppSearchSchema.newPropertyBuilder(KEY_FROM)
                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
                        .build()

                ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_TO)
                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
                        .build()

                ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_CC)
                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
                        .build()

                ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BCC)
                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
                        .build()

                ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_SUBJECT)
                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
                        .build()

                ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BODY)
                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
                        .build()

                ).build();

        /**
         * Creates a new {@link Email.Builder}.
@@ -603,6 +639,15 @@ public final class AppSearch {
            return new Builder(uri);
        }

        /**
         * Creates a new {@link Email} from the contents of an existing {@link Document}.
         *
         * @param document The {@link Document} containing the email content.
         */
        public Email(@NonNull Document document) {
            super(document);
        }

        /**
         * Get the from address of {@link Email}.
         *
@@ -615,10 +660,10 @@ public final class AppSearch {
        }

        /**
         * Get the destination address of {@link Email}.
         * Get the destination addresses of {@link Email}.
         *
         * @return Returns the destination address of {@link Email} or {@code null} if it's not been
         *         set yet.
         * @return Returns the destination addresses of {@link Email} or {@code null} if it's not
         *         been set yet.
         * @hide
         */
        @Nullable
+12 −12
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ public class AppSearchManager {
    }

    /**
     * Sets the schema being used by documents provided to the #put method.
     * Sets the schema being 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
@@ -106,13 +106,12 @@ public class AppSearchManager {
     *
     * @hide
     */
    // TODO(b/143789408): linkify #put after that API is created
    public void setSchema(@NonNull AppSearchSchema... schemas) {
        setSchema(Arrays.asList(schemas), /*forceOverride=*/false);
    }

    /**
     * Sets the schema being used by documents provided to the #put method.
     * Sets the schema being used by documents provided to the {@link #putDocuments} method.
     *
     * <p>This method is similar to {@link #setSchema(AppSearchSchema...)}, except for the
     * {@code forceOverride} parameter. If a backwards-incompatible schema is specified but the
@@ -129,7 +128,6 @@ public class AppSearchManager {
     *
     * @hide
     */
    // TODO(b/143789408): linkify #put after that API is created
    public void setSchema(@NonNull List<AppSearchSchema> schemas, boolean forceOverride) {
        // Prepare the merged schema for transmission.
        SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder();
@@ -151,26 +149,28 @@ public class AppSearchManager {
    }

    /**
     * Index {@link Document} to AppSearch
     * Index {@link android.app.appsearch.AppSearch.Document Documents} into AppSearch.
     *
     * <p>You should not call this method directly; instead, use the {@code AppSearch#put()} API
     * provided by JetPack.
     * <p>You should not call this method directly; instead, use the
     * {@code AppSearch#putDocuments()} API provided by JetPack.
     *
     * <p>The schema should be set via {@link #setSchema} method.
     * <p>Each {@link AppSearch.Document Document's} {@code schemaType} field must be set to the
     * name of a schema type previously registered via the {@link #setSchema} method.
     *
     * @param documents {@link Document Documents} that need to be indexed.
     * @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}.
     * @param callback Callback to receive errors. On success, it will be called with {@code null}.
     *     On failure, it will be called with a {@link Throwable} describing the failure.
     */
    public void put(@NonNull List<Document> documents,
    public void putDocuments(
            @NonNull List<Document> documents,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull Consumer<? super Throwable> callback) {
        AndroidFuture<Void> future = new AndroidFuture<>();
        for (Document document : documents) {
            // TODO(b/146386470) batching Document protos
            try {
                mService.put(document.getProto().toByteArray(), future);
                mService.putDocument(document.getProto().toByteArray(), future);
            } catch (RemoteException e) {
                future.completeExceptionally(e);
                break;
+13 −3
Original line number Diff line number Diff line
@@ -22,15 +22,25 @@ interface IAppSearchManager {
    /**
     * Sets the schema.
     *
     * @param schemaProto Serialized SchemaProto.
     * @param schemaBytes Serialized SchemaProto.
     * @param forceOverride Whether to apply the new schema even if it is incompatible. All
     *     incompatible documents will be deleted.
     * @param callback {@link AndroidFuture}&lt;{@link Void}&gt;. Will be completed with
     *     {@code null} upon successful completion of the setSchema call, or completed
     *     exceptionally if setSchema fails.
     */
    void setSchema(in byte[] schemaProto, boolean forceOverride, in AndroidFuture callback);
    void put(in byte[] documentBytes, in AndroidFuture callback);
    void setSchema(in byte[] schemaBytes, boolean forceOverride, in AndroidFuture callback);

    /**
     * Inserts a document into the index.
     *
     * @param documentBytes serialized DocumentProto
     * @param callback {@link AndroidFuture}&lt;{@link Void}&gt;. Will be completed with
     *     {@code null} upon successful completion of the put call, or completed exceptionally if
     *     put fails.
     */
    void putDocument(in byte[] documentBytes, in AndroidFuture callback);

    /**
     * Searches a document based on a given query string.
     *
+13 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.server.appsearch.impl.AppSearchImpl;
import com.android.server.appsearch.impl.FakeIcing;
import com.android.server.appsearch.impl.ImplInstanceManager;

import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.SchemaProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchSpecProto;
@@ -71,11 +72,21 @@ public class AppSearchManagerService extends SystemService {
        }

        @Override
        public void put(byte[] documentBytes, AndroidFuture callback) {
        public void putDocument(byte[] documentBytes, AndroidFuture callback) {
            Preconditions.checkNotNull(documentBytes);
            Preconditions.checkNotNull(callback);
            int callingUid = Binder.getCallingUidOrThrow();
            int callingUserId = UserHandle.getUserId(callingUid);
            long callingIdentity = Binder.clearCallingIdentity();
            try {
                throw new UnsupportedOperationException("Put document not yet implemented");
                DocumentProto document = DocumentProto.parseFrom(documentBytes);
                AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                impl.putDocument(callingUid, document);
                callback.complete(null);
            } catch (Throwable t) {
                callback.completeExceptionally(t);
            } finally {
                Binder.restoreCallingIdentity(callingIdentity);
            }
        }
        // TODO(sidchhabra):Init FakeIcing properly.
+56 −0
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import android.content.Context;

import com.android.internal.annotations.VisibleForTesting;

import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.PropertyConfigProto;
import com.google.android.icing.proto.PropertyProto;
import com.google.android.icing.proto.SchemaProto;
import com.google.android.icing.proto.SchemaTypeConfigProto;

@@ -94,6 +96,60 @@ public final class AppSearchImpl {
        }
    }

    /**
     * Adds a document to the AppSearch index.
     *
     * @param callingUid The uid of the app calling AppSearch.
     * @param origDocument The document to index.
     */
    public void putDocument(int callingUid, @NonNull DocumentProto origDocument) {
        // Rewrite the type names to include the app's prefix
        String typePrefix = getTypePrefix(callingUid);
        DocumentProto.Builder documentBuilder = origDocument.toBuilder();
        rewriteDocumentTypes(typePrefix, documentBuilder);
        mFakeIcing.put(documentBuilder.build());
    }

    /**
     * Rewrites all types mentioned anywhere in {@code documentBuilder} to prepend
     * {@code typePrefix}.
     *
     * @param typePrefix The prefix to add
     * @param documentBuilder The document to mutate
     */
    @VisibleForTesting
    void rewriteDocumentTypes(
            @NonNull String typePrefix,
            @NonNull DocumentProto.Builder documentBuilder) {
        // Rewrite the type name to include the app's prefix
        String newSchema = typePrefix + documentBuilder.getSchema();
        documentBuilder.setSchema(newSchema);

        // Add namespace. If we ever allow users to set their own namespaces, this will have
        // to change to prepend the prefix instead of setting the whole namespace. We will also have
        // to store the namespaces in a map similar to the type map so we can rewrite queries with
        // empty namespaces.
        documentBuilder.setNamespace(typePrefix);

        // Recurse into derived documents
        for (int propertyIdx = 0;
                propertyIdx < documentBuilder.getPropertiesCount();
                propertyIdx++) {
            int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
            if (documentCount > 0) {
                PropertyProto.Builder propertyBuilder =
                        documentBuilder.getProperties(propertyIdx).toBuilder();
                for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
                    DocumentProto.Builder derivedDocumentBuilder =
                            propertyBuilder.getDocumentValues(documentIdx).toBuilder();
                    rewriteDocumentTypes(typePrefix, derivedDocumentBuilder);
                    propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
                }
                documentBuilder.setProperties(propertyIdx, propertyBuilder);
            }
        }
    }

   /**
     * Returns a type prefix in a format like {@code com.example.package@1000/} or
     * {@code com.example.sharedname:5678@1000/}.
Loading