Merge request objects from Jetpack into Framework.

Bug: 162450968
Test: AppSearchManagerTest
Change-Id: I24e9de7495cee8aa7635b69e4817bc5e4350120a
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index b38bb05..67fa6c8 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -22,9 +22,9 @@
 import android.os.RemoteException;
 
 import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
@@ -96,46 +96,23 @@
      * <p>It is a no-op to set the same schema as has been previously set; this is handled
      * efficiently.
      *
-     * @param schemas The schema configs for the types used by the calling app.
+     * @param request The schema update request.
      * @return the result of performing this operation.
      *
      * @hide
      */
     @NonNull
-    public AppSearchResult<Void> setSchema(@NonNull AppSearchSchema... schemas) {
-        return setSchema(Arrays.asList(schemas), /*forceOverride=*/false);
-    }
-
-    /**
-     * 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
-     * {@code forceOverride} parameter is set to {@code true}, instead of returning an
-     * {@link AppSearchResult} with the {@link AppSearchResult#RESULT_INVALID_SCHEMA} code, all
-     * documents which are not compatible with the new schema will be deleted and the incompatible
-     * schema will be applied.
-     *
-     * @param schemas The schema configs for the types used by the calling app.
-     * @param forceOverride Whether to force the new schema to be applied even if there are
-     *     incompatible changes versus the previously set schema. Documents which are incompatible
-     *     with the new schema will be deleted.
-     * @return the result of performing this operation.
-     *
-     * @hide
-     */
-    @NonNull
-    public AppSearchResult<Void> setSchema(
-            @NonNull List<AppSearchSchema> schemas, boolean forceOverride) {
+    public AppSearchResult<Void> setSchema(@NonNull SetSchemaRequest request) {
+        Preconditions.checkNotNull(request);
         // TODO: This should use com.android.internal.infra.RemoteStream or another mechanism to
         //  avoid binder limits.
-        List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
-        for (AppSearchSchema schema : schemas) {
+        List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size());
+        for (AppSearchSchema schema : request.getSchemas()) {
             schemaBundles.add(schema.getBundle());
         }
         AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
         try {
-            mService.setSchema(schemaBundles, forceOverride, future);
+            mService.setSchema(schemaBundles, request.isForceOverride(), future);
         } catch (RemoteException e) {
             future.completeExceptionally(e);
         }
@@ -151,19 +128,20 @@
      * <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 documents {@link GenericDocument}s that need to be indexed.
-     * @return An {@link AppSearchBatchResult} mapping the document URIs to {@link Void} if they
-     *     were successfully indexed, or a {@link Throwable} describing the failure if they could
-     *     not be indexed.
+     * @param request {@link PutDocumentsRequest} containing documents to be indexed
+     * @return The pending result of performing this operation. The keys of the returned
+     * {@link AppSearchBatchResult} are the URIs of the input documents. The values are
+     * {@code null} if they were successfully indexed, or a failed {@link AppSearchResult}
+     * otherwise.
      * @hide
      */
-    public AppSearchBatchResult<String, Void> putDocuments(
-            @NonNull List<GenericDocument> documents) {
+    public AppSearchBatchResult<String, Void> putDocuments(@NonNull PutDocumentsRequest request) {
         // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in
         // one big list.
+        List<GenericDocument> documents = request.getDocuments();
         List<Bundle> documentBundles = new ArrayList<>(documents.size());
-        for (GenericDocument document : documents) {
-            documentBundles.add(document.getBundle());
+        for (int i = 0; i < documents.size(); i++) {
+            documentBundles.add(documents.get(i).getBundle());
         }
         AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
         try {
@@ -180,15 +158,18 @@
      * <p>You should not call this method directly; instead, use the
      * {@code AppSearch#getDocuments()} API provided by JetPack.
      *
-     * @param uris URIs of the documents to look up.
-     * @return An {@link AppSearchBatchResult} mapping the document URIs to
-     *     {@link GenericDocument} 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.
+     * @param request {@link GetByUriRequest} containing URIs to be retrieved.
+     * @return The pending result of performing this operation. The keys of the returned
+     * {@link AppSearchBatchResult} are the input URIs. The values are the returned
+     * {@link GenericDocument}s on success, or a failed {@link AppSearchResult} otherwise.
+     * URIs that are not found will return a failed {@link AppSearchResult} with a result code
+     * of {@link AppSearchResult#RESULT_NOT_FOUND}.
      */
-    public AppSearchBatchResult<String, GenericDocument> getDocuments(@NonNull List<String> uris) {
+    public AppSearchBatchResult<String, GenericDocument> getByUri(
+            @NonNull GetByUriRequest request) {
         // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending
         //     them in one big list.
+        List<String> uris = new ArrayList<>(request.getUris());
         AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
         try {
             mService.getDocuments(uris, future);
@@ -300,12 +281,15 @@
      * <p>You should not call this method directly; instead, use the {@code AppSearch#delete()} API
      * provided by JetPack.
      *
-     * @param uris URIs of the documents to delete
-     * @return An {@link AppSearchBatchResult} mapping each URI to a {@code null} success if
-     *     deletion was successful, to a {@code null} failure if the document did not exist, or to a
-     *     {@code throwable} failure if deletion failed for another reason.
+     * @param request Request containing URIs to be removed.
+     * @return The pending result of performing this operation. The keys of the returned
+     * {@link AppSearchBatchResult} are the input URIs. The values are {@code null} on success,
+     * or a failed {@link AppSearchResult} otherwise. URIs that are not found will return a
+     * failed {@link AppSearchResult} with a result code of
+     * {@link AppSearchResult#RESULT_NOT_FOUND}.
      */
-    public AppSearchBatchResult<String, Void> delete(@NonNull List<String> uris) {
+    public AppSearchBatchResult<String, Void> removeByUri(@NonNull RemoveByUriRequest request) {
+        List<String> uris = new ArrayList<>(request.getUris());
         AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
         try {
             mService.delete(uris, future);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
new file mode 100644
index 0000000..3c0e746
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.NonNull;
+
+import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to retrieve documents by namespace and URI.
+ *
+ * @see AppSearchManager#getByUri
+ * @hide
+ */
+public final class GetByUriRequest {
+    private final String mNamespace;
+    private final Set<String> mUris;
+
+    GetByUriRequest(@NonNull String namespace, @NonNull Set<String> uris) {
+        mNamespace = namespace;
+        mUris = uris;
+    }
+
+    /** @hide */
+    
+    @NonNull
+    public String getNamespace() {
+        return mNamespace;
+    }
+
+    /** @hide */
+    
+    @NonNull
+    public Set<String> getUris() {
+        return mUris;
+    }
+
+    /** Builder for {@link GetByUriRequest} objects. */
+    public static final class Builder {
+        private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
+        private final Set<String> mUris = new ArraySet<>();
+        private boolean mBuilt = false;
+
+        /**
+         * Sets which namespace these documents will be retrieved from.
+         *
+         * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
+         */
+        @NonNull
+        public Builder setNamespace(@NonNull String namespace) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(namespace);
+            mNamespace = namespace;
+            return this;
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUris(@NonNull String... uris) {
+            Preconditions.checkNotNull(uris);
+            return addUris(Arrays.asList(uris));
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUris(@NonNull Collection<String> uris) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(uris);
+            mUris.addAll(uris);
+            return this;
+        }
+
+        /** Builds a new {@link GetByUriRequest}. */
+        @NonNull
+        public GetByUriRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new GetByUriRequest(mNamespace, mUris);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
new file mode 100644
index 0000000..7e97542
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Encapsulates a request to index a document into an {@link AppSearchManager} database.
+ *
+ * @see AppSearchManager#putDocuments
+ * @hide
+ */
+public final class PutDocumentsRequest {
+    private final List<GenericDocument> mDocuments;
+
+    PutDocumentsRequest(List<GenericDocument> documents) {
+        mDocuments = documents;
+    }
+
+    /** @hide */
+    
+    @NonNull
+    public List<GenericDocument> getDocuments() {
+        return mDocuments;
+    }
+
+    /** Builder for {@link PutDocumentsRequest} objects. */
+    public static final class Builder {
+        private final List<GenericDocument> mDocuments = new ArrayList<>();
+        private boolean mBuilt = false;
+
+        /** Adds one or more documents to the request. */
+        @NonNull
+        public Builder addGenericDocument(@NonNull GenericDocument... documents) {
+            Preconditions.checkNotNull(documents);
+            return addGenericDocument(Arrays.asList(documents));
+        }
+
+        /** Adds one or more documents to the request. */
+        @NonNull
+        public Builder addGenericDocument(@NonNull Collection<GenericDocument> documents) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(documents);
+            mDocuments.addAll(documents);
+            return this;
+        }
+
+        /** Builds a new {@link PutDocumentsRequest}. */
+        @NonNull
+        public PutDocumentsRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new PutDocumentsRequest(mDocuments);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
new file mode 100644
index 0000000..a047041
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.NonNull;
+
+import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to remove documents by namespace and URI.
+ *
+ * @see AppSearchManager#removeByUri
+ * @hide
+ */
+public final class RemoveByUriRequest {
+    private final String mNamespace;
+    private final Set<String> mUris;
+
+    RemoveByUriRequest(String namespace, Set<String> uris) {
+        mNamespace = namespace;
+        mUris = uris;
+    }
+
+    /** @hide */
+    
+    @NonNull
+    public String getNamespace() {
+        return mNamespace;
+    }
+
+    /** @hide */
+    
+    @NonNull
+    public Set<String> getUris() {
+        return mUris;
+    }
+
+    /** Builder for {@link RemoveByUriRequest} objects. */
+    public static final class Builder {
+        private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
+        private final Set<String> mUris = new ArraySet<>();
+        private boolean mBuilt = false;
+
+        /**
+         * Sets which namespace these documents will be removed from.
+         *
+         * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
+         */
+        @NonNull
+        public Builder setNamespace(@NonNull String namespace) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(namespace);
+            mNamespace = namespace;
+            return this;
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUris(@NonNull String... uris) {
+            Preconditions.checkNotNull(uris);
+            return addUris(Arrays.asList(uris));
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUris(@NonNull Collection<String> uris) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(uris);
+            mUris.addAll(uris);
+            return this;
+        }
+
+        /** Builds a new {@link RemoveByUriRequest}. */
+        @NonNull
+        public RemoveByUriRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new RemoveByUriRequest(mNamespace, mUris);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
new file mode 100644
index 0000000..b2e9d46
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.NonNull;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to update the schema of an {@link AppSearchManager} database.
+ *
+ * @see AppSearchManager#setSchema
+ * @hide
+ */
+public final class SetSchemaRequest {
+    private final Set<AppSearchSchema> mSchemas;
+    private final boolean mForceOverride;
+
+    SetSchemaRequest(Set<AppSearchSchema> schemas, boolean forceOverride) {
+        mSchemas = schemas;
+        mForceOverride = forceOverride;
+    }
+
+    /** @hide */
+    
+    @NonNull
+    public Set<AppSearchSchema> getSchemas() {
+        return mSchemas;
+    }
+
+    /** @hide */
+    
+    public boolean isForceOverride() {
+        return mForceOverride;
+    }
+
+    /** Builder for {@link SetSchemaRequest} objects. */
+    public static final class Builder {
+        private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
+        private boolean mForceOverride = false;
+        private boolean mBuilt = false;
+
+        /** Adds one or more types to the schema. */
+        @NonNull
+        public Builder addSchema(@NonNull AppSearchSchema... schemas) {
+            Preconditions.checkNotNull(schemas);
+            return addSchema(Arrays.asList(schemas));
+        }
+
+        /** Adds one or more types to the schema. */
+        @NonNull
+        public Builder addSchema(@NonNull Collection<AppSearchSchema> schemas) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(schemas);
+            mSchemas.addAll(schemas);
+            return this;
+        }
+
+        /**
+         * Configures the {@link SetSchemaRequest} to delete any existing documents that don't
+         * follow the new schema.
+         *
+         * <p>By default, this is {@code false} and schema incompatibility causes the
+         * {@link AppSearchManager#setSchema} call to fail.
+         *
+         * @see AppSearchManager#setSchema
+         */
+        @NonNull
+        public Builder setForceOverride(boolean forceOverride) {
+            mForceOverride = forceOverride;
+            return this;
+        }
+
+        /** Builds a new {@link SetSchemaRequest}. */
+        @NonNull
+        public SetSchemaRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new SetSchemaRequest(mSchemas, mForceOverride);
+        }
+    }
+}