From 0e8fa4e65b13484191aea0ab1cd8edd9e73cdda6 Mon Sep 17 00:00:00 2001 From: Alexander Dorokhine Date: Mon, 13 Jan 2020 20:22:20 -0800 Subject: [PATCH] Add a SetSchema API and builders. They directly construct the proto in frameworks.jar. The API is not yet implemented. Test: atest CtsAppSearchTestCases Bug: 145635424 Change-Id: I4f708fa845a87f171ace437788d2c45161fc38ff --- Android.bp | 3 +- apex/appsearch/framework/Android.bp | 43 +- .../app/appsearch/AppSearchManager.java | 75 +++- .../app/appsearch/AppSearchSchema.java | 423 ++++++++++++++++++ .../app/appsearch/IAppSearchManager.aidl | 12 + .../app/appsearch/IllegalSchemaException.java | 36 ++ apex/appsearch/service/Android.bp | 23 +- .../appsearch/AppSearchManagerService.java | 12 + .../server/appsearch/impl/FakeIcing.java | 2 - 9 files changed, 587 insertions(+), 42 deletions(-) create mode 100644 apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java create mode 100644 apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java diff --git a/Android.bp b/Android.bp index 4e2b156afbbf..a7ac094e1b56 100644 --- a/Android.bp +++ b/Android.bp @@ -509,7 +509,8 @@ java_library { static_libs: [ "exoplayer2-core", "android.hardware.wifi-V1.0-java-constants", - ], + ], + libs: ["icing-java-proto-lite"], apex_available: ["//apex_available:platform"], } diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp index 1f30dda21ef7..2e8811506e0b 100644 --- a/apex/appsearch/framework/Android.bp +++ b/apex/appsearch/framework/Android.bp @@ -13,29 +13,32 @@ // limitations under the License. filegroup { - name: "framework-appsearch-sources", - srcs: [ - "java/**/*.java", - "java/**/*.aidl", - ], - path: "java", + name: "framework-appsearch-sources", + srcs: [ + "java/**/*.java", + "java/**/*.aidl", + ], + path: "java", } java_library { - name: "framework-appsearch", - installable: true, - sdk_version: "core_platform", // TODO(b/146218515) should be core_current - srcs: [":framework-appsearch-sources"], - hostdex: true, // for hiddenapi check - libs: [ - "framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs - ], - visibility: [ - "//frameworks/base/apex/appsearch:__subpackages__", - // TODO(b/146218515) remove this when framework is built with the stub of appsearch - "//frameworks/base", - ], - apex_available: ["com.android.appsearch"], + name: "framework-appsearch", + installable: true, + sdk_version: "core_platform", // TODO(b/146218515) should be core_current + srcs: [":framework-appsearch-sources"], + hostdex: true, // for hiddenapi check + libs: [ + "framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs + ], + static_libs: [ + "icing-java-proto-lite", + ], + visibility: [ + "//frameworks/base/apex/appsearch:__subpackages__", + // TODO(b/146218515) remove this when framework is built with the stub of appsearch + "//frameworks/base", + ], + apex_available: ["com.android.appsearch"], } metalava_appsearch_docs_args = diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index a8ee35c129eb..58bb6056db98 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -15,21 +15,84 @@ */ package android.app.appsearch; +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; import android.annotation.SystemService; import android.content.Context; +import android.os.RemoteException; + +import com.android.internal.infra.AndroidFuture; + +import com.google.android.icing.proto.SchemaProto; + +import java.util.concurrent.Executor; +import java.util.function.Consumer; /** - * TODO(b/142567528): add comments when implement this class + * This class provides access to the centralized AppSearch index maintained by the system. + * + *

Apps can index structured text documents with AppSearch, which can then be retrieved through + * the query API. + * * @hide */ @SystemService(Context.APP_SEARCH_SERVICE) public class AppSearchManager { private final IAppSearchManager mService; - /** - * TODO(b/142567528): add comments when implement this class - * @hide - */ - public AppSearchManager(IAppSearchManager service) { + + /** @hide */ + public AppSearchManager(@NonNull IAppSearchManager service) { mService = service; } + + /** + * Sets the schema being used by documents provided to the #put method. + * + *

This operation is performed asynchronously. On success, the provided callback will be + * called with {@code null}. On failure, the provided callback will be called with a + * {@link Throwable} describing the failure. + * + *

It is a no-op to set the same schema as has been previously set; this is handled + * efficiently. + * + *

AppSearch automatically handles the following types of schema changes: + *

+ * + *

This method will return an error when attempting to make the following types of changes: + *

+ * + * @param schema The schema config for this app. + * @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}. + * + * @hide + */ + // TODO(b/143789408): linkify #put after that API is created + // TODO(b/145635424): add a 'force' param to setSchema after the corresponding API is finalized + // in Icing Library + // TODO(b/145635424): Update the documentation above once the Schema mutation APIs of Icing + // Library are finalized + public void setSchema( + @NonNull AppSearchSchema schema, + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer callback) { + SchemaProto schemaProto = schema.getProto(); + byte[] schemaBytes = schemaProto.toByteArray(); + AndroidFuture future = new AndroidFuture<>(); + try { + mService.setSchema(schemaBytes, future); + } catch (RemoteException e) { + future.completeExceptionally(e); + } + future.whenCompleteAsync((noop, err) -> callback.accept(err), executor); + } } diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java new file mode 100644 index 000000000000..b5d903a3206e --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2019 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.IntDef; +import android.annotation.NonNull; + +import com.google.android.icing.proto.PropertyConfigProto; +import com.google.android.icing.proto.SchemaProto; +import com.google.android.icing.proto.SchemaTypeConfigProto; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Representation of the AppSearch Schema. + * + *

The schema is the set of document types, properties, and config (like tokenization type) + * understood by AppSearch for this app. + * + * @hide + */ +public final class AppSearchSchema { + private final SchemaProto mProto; + + private AppSearchSchema(SchemaProto proto) { + mProto = proto; + } + + /** Creates a new {@link AppSearchSchema.Builder}. */ + @NonNull + public static AppSearchSchema.Builder newBuilder() { + return new AppSearchSchema.Builder(); + } + + /** Creates a new {@link SchemaType.Builder}. */ + @NonNull + public static SchemaType.Builder newSchemaTypeBuilder(@NonNull String typeName) { + return new SchemaType.Builder(typeName); + } + + /** Creates a new {@link PropertyConfig.Builder}. */ + @NonNull + public static PropertyConfig.Builder newPropertyBuilder(@NonNull String propertyName) { + return new PropertyConfig.Builder(propertyName); + } + + /** Creates a new {@link IndexingConfig.Builder}. */ + @NonNull + public static IndexingConfig.Builder newIndexingConfigBuilder() { + return new IndexingConfig.Builder(); + } + + /** + * Returns the schema proto populated by the {@link AppSearchSchema} builders. + * @hide + */ + @NonNull + SchemaProto getProto() { + return mProto; + } + + /** Builder for {@link AppSearchSchema objects}. */ + public static final class Builder { + private final SchemaProto.Builder mProtoBuilder = SchemaProto.newBuilder(); + + private Builder() {} + + /** Adds a supported type to this app's AppSearch schema. */ + @NonNull + public AppSearchSchema.Builder addType(@NonNull SchemaType schemaType) { + mProtoBuilder.addTypes(schemaType.mProto); + return this; + } + + /** + * Constructs a new {@link AppSearchSchema} from the contents of this builder. + * + *

After calling this method, the builder must no longer be used. + */ + @NonNull + public AppSearchSchema build() { + return new AppSearchSchema(mProtoBuilder.build()); + } + } + + /** + * Represents a type of a document. + * + *

For example, an e-mail message or a music recording could be a schema type. + */ + public static final class SchemaType { + private final SchemaTypeConfigProto mProto; + + private SchemaType(SchemaTypeConfigProto proto) { + mProto = proto; + } + + /** Builder for {@link SchemaType} objects. */ + public static final class Builder { + private final SchemaTypeConfigProto.Builder mProtoBuilder = + SchemaTypeConfigProto.newBuilder(); + + private Builder(@NonNull String typeName) { + mProtoBuilder.setSchemaType(typeName); + } + + /** Adds a property to the given type. */ + @NonNull + public SchemaType.Builder addProperty(@NonNull PropertyConfig propertyConfig) { + mProtoBuilder.addProperties(propertyConfig.mProto); + return this; + } + + /** + * Constructs a new {@link SchemaType} from the contents of this builder. + * + *

After calling this method, the builder must no longer be used. + */ + @NonNull + public SchemaType build() { + return new SchemaType(mProtoBuilder.build()); + } + } + } + + /** + * Configuration for a single property (field) of a document type. + * + *

For example, an {@code EmailMessage} would be a type and the {@code subject} would be + * a property. + */ + public static final class PropertyConfig { + /** Physical data-types of the contents of the property. */ + // NOTE: The integer values of these constants must match the proto enum constants in + // com.google.android.icing.proto.PropertyConfigProto.DataType.Code. + @IntDef(prefix = {"DATA_TYPE_"}, value = { + DATA_TYPE_STRING, + DATA_TYPE_INT64, + DATA_TYPE_DOUBLE, + DATA_TYPE_BOOLEAN, + DATA_TYPE_BYTES, + DATA_TYPE_DOCUMENT, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DataType {} + + public static final int DATA_TYPE_STRING = 1; + public static final int DATA_TYPE_INT64 = 2; + public static final int DATA_TYPE_DOUBLE = 3; + public static final int DATA_TYPE_BOOLEAN = 4; + + /** Unstructured BLOB. */ + public static final int DATA_TYPE_BYTES = 5; + + /** + * Indicates that the property itself is an Document, making it part a hierarchical + * Document schema. Any property using this DataType MUST have a valid + * {@code schemaType}. + */ + public static final int DATA_TYPE_DOCUMENT = 6; + + /** The cardinality of the property (whether it is required, optional or repeated). */ + // NOTE: The integer values of these constants must match the proto enum constants in + // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code. + @IntDef(prefix = {"CARDINALITY_"}, value = { + CARDINALITY_REPEATED, + CARDINALITY_OPTIONAL, + CARDINALITY_REQUIRED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Cardinality {} + + /** Any number of items (including zero) [0...*]. */ + public static final int CARDINALITY_REPEATED = 1; + + /** Zero or one value [0,1]. */ + public static final int CARDINALITY_OPTIONAL = 2; + + /** Exactly one value [1]. */ + public static final int CARDINALITY_REQUIRED = 3; + + private final PropertyConfigProto mProto; + + private PropertyConfig(PropertyConfigProto proto) { + mProto = proto; + } + + /** + * Builder for {@link PropertyConfig}. + * + *

The following properties must be set, or {@link PropertyConfig} construction will + * fail: + *

+ * + *

In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType} + * is also required. + */ + public static final class Builder { + private final PropertyConfigProto.Builder mProtoBuilder = + PropertyConfigProto.newBuilder(); + + private Builder(String propertyName) { + mProtoBuilder.setPropertyName(propertyName); + } + + /** + * Type of data the property contains (e.g. string, int, bytes, etc). + * + *

This property must be set. + */ + @NonNull + public PropertyConfig.Builder setDataType(@DataType int dataType) { + PropertyConfigProto.DataType.Code dataTypeProto = + PropertyConfigProto.DataType.Code.forNumber(dataType); + if (dataTypeProto == null) { + throw new IllegalArgumentException("Invalid dataType: " + dataType); + } + mProtoBuilder.setDataType(dataTypeProto); + return this; + } + + /** + * The logical schema-type of the contents of this property. + * + *

Only required when {@link #setDataType(int)} is set to + * {@link #DATA_TYPE_DOCUMENT}. Otherwise, it is ignored. + */ + @NonNull + public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) { + mProtoBuilder.setSchemaType(schemaType); + return this; + } + + /** + * The cardinality of the property (whether it is optional, required or repeated). + * + *

This property must be set. + */ + @NonNull + public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) { + PropertyConfigProto.Cardinality.Code cardinalityProto = + PropertyConfigProto.Cardinality.Code.forNumber(cardinality); + if (cardinalityProto == null) { + throw new IllegalArgumentException("Invalid cardinality: " + cardinality); + } + mProtoBuilder.setCardinality(cardinalityProto); + return this; + } + + /** + * Configures how this property should be indexed. + * + *

If this is not supplied, the property will not be indexed at all. + */ + @NonNull + public PropertyConfig.Builder setIndexingConfig( + @NonNull IndexingConfig indexingConfig) { + mProtoBuilder.setIndexingConfig(indexingConfig.mProto); + return this; + } + + /** + * Constructs a new {@link PropertyConfig} from the contents of this builder. + * + *

After calling this method, the builder must no longer be used. + * + * @throws IllegalSchemaException If the property is not correctly populated (e.g. + * missing {@code dataType}). + */ + @NonNull + public PropertyConfig build() { + if (mProtoBuilder.getDataType() == PropertyConfigProto.DataType.Code.UNKNOWN) { + throw new IllegalSchemaException("Missing dataType field"); + } + if (mProtoBuilder.getSchemaType().isEmpty() + && mProtoBuilder.getDataType() + == PropertyConfigProto.DataType.Code.DOCUMENT) { + throw new IllegalSchemaException( + "Missing field: schemaType (required for configs with " + + "dataType = DOCUMENT)"); + } + if (mProtoBuilder.getCardinality() + == PropertyConfigProto.Cardinality.Code.UNKNOWN) { + throw new IllegalSchemaException("Missing cardinality field"); + } + return new PropertyConfig(mProtoBuilder.build()); + } + } + } + + /** Configures how a property should be indexed so that it can be retrieved by queries. */ + public static final class IndexingConfig { + /** Encapsulates the configurations on how AppSearch should query/index these terms. */ + // NOTE: The integer values of these constants must match the proto enum constants in + // com.google.android.icing.proto.TermMatchType.Code. + @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = { + TERM_MATCH_TYPE_UNKNOWN, + TERM_MATCH_TYPE_EXACT_ONLY, + TERM_MATCH_TYPE_PREFIX, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TermMatchType {} + + /** + * Content in this property will not be tokenized or indexed. + * + *

Useful if the data type is not made up of terms (e.g. + * {@link PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES} + * type). All the properties inside the nested property won't be indexed regardless of the + * value of {@code termMatchType} for the nested properties. + */ + public static final int TERM_MATCH_TYPE_UNKNOWN = 0; + + /** + * Content in this property should only be returned for queries matching the exact tokens + * appearing in this property. + * + *

Ex. A property with "fool" should NOT match a query for "foo". + */ + public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1; + + /** + * Content in this property should be returned for queries that are either exact matches or + * query matches of the tokens appearing in this property. + * + *

Ex. A property with "fool" should match a query for "foo". + */ + public static final int TERM_MATCH_TYPE_PREFIX = 2; + + /** Configures how tokens should be extracted from this property. */ + // NOTE: The integer values of these constants must match the proto enum constants in + // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code. + @IntDef(prefix = {"TOKENIZER_TYPE_"}, value = { + TOKENIZER_TYPE_NONE, + TOKENIZER_TYPE_PLAIN, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TokenizerType {} + + /** + * It is only valid for tokenizer_type to be 'NONE' if the data type is + * {@link PropertyConfig#DATA_TYPE_DOCUMENT}. + */ + public static final int TOKENIZER_TYPE_NONE = 0; + + /** Tokenization for plain text. */ + public static final int TOKENIZER_TYPE_PLAIN = 1; + + private final com.google.android.icing.proto.IndexingConfig mProto; + + private IndexingConfig(com.google.android.icing.proto.IndexingConfig proto) { + mProto = proto; + } + + /** + * Builder for {@link IndexingConfig} objects. + * + *

You may skip adding an {@link IndexingConfig} for a property, which is equivalent to + * an {@link IndexingConfig} having {@code termMatchType} equal to + * {@link #TERM_MATCH_TYPE_UNKNOWN}. In this case the property will not be indexed. + */ + public static final class Builder { + private final com.google.android.icing.proto.IndexingConfig.Builder mProtoBuilder = + com.google.android.icing.proto.IndexingConfig.newBuilder(); + + private Builder() {} + + /** Configures how the content of this property should be matched in the index. */ + @NonNull + public IndexingConfig.Builder setTermMatchType(@TermMatchType int termMatchType) { + com.google.android.icing.proto.TermMatchType.Code termMatchTypeProto = + com.google.android.icing.proto.TermMatchType.Code.forNumber(termMatchType); + if (termMatchTypeProto == null) { + throw new IllegalArgumentException("Invalid termMatchType: " + termMatchType); + } + mProtoBuilder.setTermMatchType(termMatchTypeProto); + return this; + } + + /** Configures how this property should be tokenized (split into words). */ + @NonNull + public IndexingConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) { + com.google.android.icing.proto.IndexingConfig.TokenizerType.Code + tokenizerTypeProto = + com.google.android.icing.proto.IndexingConfig + .TokenizerType.Code.forNumber(tokenizerType); + if (tokenizerTypeProto == null) { + throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType); + } + mProtoBuilder.setTokenizerType(tokenizerTypeProto); + return this; + } + + /** + * Constructs a new {@link IndexingConfig} from the contents of this builder. + * + *

After calling this method, the builder must no longer be used. + */ + @NonNull + public IndexingConfig build() { + return new IndexingConfig(mProtoBuilder.build()); + } + } + } +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl index f0f4f512d769..8085aa8b006c 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl @@ -14,6 +14,18 @@ * limitations under the License. */ package android.app.appsearch; + +import com.android.internal.infra.AndroidFuture; + /** {@hide} */ interface IAppSearchManager { + /** + * Sets the schema. + * + * @param schemaProto serialized SchemaProto + * @param callback {@link AndroidFuture}<{@link Void}>. Will be completed with + * {@code null} upon successful completion of the setSchema call, or completed exceptionally + * if setSchema fails. + */ + void setSchema(in byte[] schemaProto, in AndroidFuture callback); } diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java b/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java new file mode 100644 index 000000000000..f9e528cd2951 --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 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; + +/** + * Indicates that a {@link android.app.appsearch.AppSearchSchema} has logical inconsistencies such + * as unpopulated mandatory fields or illegal combinations of parameters. + * + * @hide + */ +public class IllegalSchemaException extends IllegalArgumentException { + /** + * Constructs a new {@link IllegalSchemaException}. + * + * @param message A developer-readable description of the issue with the bundle. + */ + public IllegalSchemaException(@NonNull String message) { + super(message); + } +} diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp index 8aed5d04a32b..73272317b5f7 100644 --- a/apex/appsearch/service/Android.bp +++ b/apex/appsearch/service/Android.bp @@ -12,17 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. java_library { - name: "service-appsearch", - installable: true, - srcs: [ - "java/**/*.java", - ], - libs: [ - "framework", - "services.core", - ], - static_libs: [ - "icing-java-proto-lite", - ], - apex_available: [ "com.android.appsearch" ], + name: "service-appsearch", + installable: true, + srcs: ["java/**/*.java"], + libs: [ + "framework", + "framework-appsearch", + "services.core", + ], + static_libs: ["icing-java-proto-lite"], + apex_available: ["com.android.appsearch"], } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index 4d44d9d04806..96316b311912 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -18,8 +18,11 @@ package com.android.server.appsearch; import android.app.appsearch.IAppSearchManager; import android.content.Context; +import com.android.internal.infra.AndroidFuture; import com.android.server.SystemService; +import com.google.android.icing.proto.SchemaProto; + /** * TODO(b/142567528): add comments when implement this class */ @@ -35,5 +38,14 @@ public class AppSearchManagerService extends SystemService { } private class Stub extends IAppSearchManager.Stub { + @Override + public void setSchema(byte[] schemaBytes, AndroidFuture callback) { + try { + SchemaProto schema = SchemaProto.parseFrom(schemaBytes); + throw new UnsupportedOperationException("setSchema not yet implemented: " + schema); + } catch (Throwable t) { + callback.completeExceptionally(t); + } + } } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java index 3dbb5cffe908..02a79a11032f 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java @@ -36,8 +36,6 @@ import java.util.concurrent.atomic.AtomicInteger; *

* Currently, only queries by single exact term are supported. There is no support for persistence, * namespaces, i18n tokenization, or schema. - * - * @hide */ public class FakeIcing { private final AtomicInteger mNextDocId = new AtomicInteger();