diff options
4 files changed, 155 insertions, 11 deletions
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java index c4e8b4157752..c4bfae98e33d 100644 --- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java +++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java @@ -72,14 +72,32 @@ public class AppFunctionRuntimeMetadata extends GenericDocument { * we need to have per-package app function schemas. * * <p>This schema should be set visible to callers from the package owner itself and for callers - * with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@link - * android.permission.EXECUTE_APP_FUNCTIONS} permissions. + * with {@link android.Manifest.permission#EXECUTE_APP_FUNCTIONS} or {@link + * android.Manifest.permission#EXECUTE_APP_FUNCTIONS_TRUSTED} permissions. * * @param packageName The package name to create a schema for. */ @NonNull public static AppSearchSchema createAppFunctionRuntimeSchema(@NonNull String packageName) { - return new AppSearchSchema.Builder(getRuntimeSchemaNameForPackage(packageName)) + return getAppFunctionRuntimeSchemaBuilder(getRuntimeSchemaNameForPackage(packageName)) + .addParentType(RUNTIME_SCHEMA_TYPE) + .build(); + } + + /** + * Creates a parent schema for all app function runtime schemas. + * + * <p>This schema should be set visible to the owner itself and for callers with {@link + * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@link + * android.permission.EXECUTE_APP_FUNCTIONS} permissions. + */ + public static AppSearchSchema createParentAppFunctionRuntimeSchema() { + return getAppFunctionRuntimeSchemaBuilder(RUNTIME_SCHEMA_TYPE).build(); + } + + private static AppSearchSchema.Builder getAppFunctionRuntimeSchemaBuilder( + @NonNull String schemaType) { + return new AppSearchSchema.Builder(schemaType) .addProperty( new AppSearchSchema.StringPropertyConfig.Builder(PROPERTY_FUNCTION_ID) .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL) @@ -111,9 +129,7 @@ public class AppFunctionRuntimeMetadata extends GenericDocument { .setJoinableValueType( AppSearchSchema.StringPropertyConfig .JOINABLE_VALUE_TYPE_QUALIFIED_ID) - .build()) - .addParentType(RUNTIME_SCHEMA_TYPE) - .build(); + .build()); } /** Returns the function id. This might look like "com.example.message#send_message". */ diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java index 6effeb3058d9..eba628dc1fba 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java +++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java @@ -25,7 +25,6 @@ import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchManager.SearchContext; import android.app.appsearch.AppSearchResult; import android.app.appsearch.AppSearchSession; -import android.app.appsearch.BatchResultCallback; import android.app.appsearch.GetSchemaResponse; import android.app.appsearch.PutDocumentsRequest; import android.app.appsearch.SearchResult; @@ -50,7 +49,6 @@ import java.util.concurrent.Executor; public class FutureAppSearchSession implements Closeable { private static final String TAG = FutureAppSearchSession.class.getSimpleName(); private final Executor mExecutor; - private final AppSearchManager mAppSearchManager; private final AndroidFuture<AppSearchResult<AppSearchSession>> mSettableSessionFuture; public FutureAppSearchSession( @@ -62,9 +60,8 @@ public class FutureAppSearchSession implements Closeable { Objects.requireNonNull(appSearchContext); mExecutor = executor; - mAppSearchManager = appSearchManager; mSettableSessionFuture = new AndroidFuture<>(); - mAppSearchManager.createSearchSession( + appSearchManager.createSearchSession( appSearchContext, mExecutor, mSettableSessionFuture::complete); } diff --git a/services/tests/appfunctions/Android.bp b/services/tests/appfunctions/Android.bp index e681fa8fec29..b5cf98697d54 100644 --- a/services/tests/appfunctions/Android.bp +++ b/services/tests/appfunctions/Android.bp @@ -37,7 +37,7 @@ android_test { "androidx.test.runner", "androidx.test.ext.truth", "platform-test-annotations", - "services.core", + "services.appfunctions", "servicestests-core-utils", "truth", "frameworks-base-testutils", diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt new file mode 100644 index 000000000000..5233f194d6c5 --- /dev/null +++ b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2023 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 com.android.server.appfunctions + +import android.app.appfunctions.AppFunctionRuntimeMetadata +import android.app.appfunctions.AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema +import android.app.appfunctions.AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema +import android.app.appsearch.AppSearchManager +import android.app.appsearch.PutDocumentsRequest +import android.app.appsearch.SearchSpec +import android.app.appsearch.SetSchemaRequest +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth.assertThat +import com.google.common.util.concurrent.MoreExecutors +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class FutureAppSearchSessionTest { + private val context = InstrumentationRegistry.getInstrumentation().targetContext + private val appSearchManager = context.getSystemService(AppSearchManager::class.java) + private val testExecutor = MoreExecutors.directExecutor() + + @Before + @After + fun clearData() { + val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build() + FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { + val setSchemaRequest = SetSchemaRequest.Builder().build() + it.setSchema(setSchemaRequest) + } + } + + @Test + fun setSchema() { + val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build() + FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { session -> + val setSchemaRequest = + SetSchemaRequest.Builder() + .addSchemas( + createParentAppFunctionRuntimeSchema(), + createAppFunctionRuntimeSchema(TEST_PACKAGE_NAME) + ) + .build() + + val schema = session.setSchema(setSchemaRequest) + + assertThat(schema.get()).isNotNull() + } + } + + @Test + fun put() { + val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build() + FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { session -> + val setSchemaRequest = + SetSchemaRequest.Builder() + .addSchemas( + createParentAppFunctionRuntimeSchema(), + createAppFunctionRuntimeSchema(TEST_PACKAGE_NAME) + ) + .build() + val schema = session.setSchema(setSchemaRequest) + assertThat(schema.get()).isNotNull() + val appFunctionRuntimeMetadata = + AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build() + val putDocumentsRequest: PutDocumentsRequest = + PutDocumentsRequest.Builder() + .addGenericDocuments(appFunctionRuntimeMetadata) + .build() + + val putResult = session.put(putDocumentsRequest) + + assertThat(putResult.get().isSuccess).isTrue() + } + } + + @Test + fun search() { + val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build() + FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { session -> + val setSchemaRequest = + SetSchemaRequest.Builder() + .addSchemas( + createParentAppFunctionRuntimeSchema(), + createAppFunctionRuntimeSchema(TEST_PACKAGE_NAME) + ) + .build() + val schema = session.setSchema(setSchemaRequest) + assertThat(schema.get()).isNotNull() + val appFunctionRuntimeMetadata = + AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build() + val putDocumentsRequest: PutDocumentsRequest = + PutDocumentsRequest.Builder() + .addGenericDocuments(appFunctionRuntimeMetadata) + .build() + val putResult = session.put(putDocumentsRequest) + assertThat(putResult.get().isSuccess).isTrue() + + val searchResult = session.search("", SearchSpec.Builder().build()) + + val genericDocs = + searchResult.get().nextPage.get().stream().map { it.genericDocument }.toList() + assertThat(genericDocs).hasSize(1) + val foundAppFunctionRuntimeMetadata = AppFunctionRuntimeMetadata(genericDocs[0]) + assertThat(foundAppFunctionRuntimeMetadata.functionId).isEqualTo(TEST_FUNCTION_ID) + } + } + + private companion object { + const val TEST_DB: String = "test_db" + const val TEST_PACKAGE_NAME: String = "test_pkg" + const val TEST_FUNCTION_ID: String = "print" + } +} |