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

Commit efde4476 authored by Oluwarotimi Adesina's avatar Oluwarotimi Adesina Committed by Android (Google) Code Review
Browse files

Merge "Introduce FutureGlobalSearchSession" into main

parents 29d12d84 bca640f6
Loading
Loading
Loading
Loading
+30 −36
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.server.appfunctions;

import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchManager;
@@ -42,10 +39,7 @@ import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * A future API wrapper of {@link AppSearchSession} APIs.
 */
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
/** A future API wrapper of {@link AppSearchSession} APIs. */
public class FutureAppSearchSession implements Closeable {
    private static final String TAG = FutureAppSearchSession.class.getSimpleName();
    private final Executor mExecutor;
@@ -67,14 +61,14 @@ public class FutureAppSearchSession implements Closeable {

    /** Converts a failed app search result codes into an exception. */
    @NonNull
    private static Exception failedResultToException(@NonNull AppSearchResult<?> appSearchResult) {
    public static Exception failedResultToException(@NonNull AppSearchResult<?> appSearchResult) {
        return switch (appSearchResult.getResultCode()) {
            case AppSearchResult.RESULT_INVALID_ARGUMENT -> new IllegalArgumentException(
                    appSearchResult.getErrorMessage());
            case AppSearchResult.RESULT_IO_ERROR -> new IOException(
                    appSearchResult.getErrorMessage());
            case AppSearchResult.RESULT_SECURITY_ERROR -> new SecurityException(
                    appSearchResult.getErrorMessage());
            case AppSearchResult.RESULT_INVALID_ARGUMENT ->
                    new IllegalArgumentException(appSearchResult.getErrorMessage());
            case AppSearchResult.RESULT_IO_ERROR ->
                    new IOException(appSearchResult.getErrorMessage());
            case AppSearchResult.RESULT_SECURITY_ERROR ->
                    new SecurityException(appSearchResult.getErrorMessage());
            default -> new IllegalStateException(appSearchResult.getErrorMessage());
        };
    }
@@ -137,12 +131,14 @@ public class FutureAppSearchSession implements Closeable {
    /** Indexes documents into the AppSearchSession database. */
    public AndroidFuture<AppSearchBatchResult<String, Void>> put(
            @NonNull PutDocumentsRequest putDocumentsRequest) {
        return getSessionAsync().thenCompose(
        return getSessionAsync()
                .thenCompose(
                        session -> {
                            AndroidFuture<AppSearchBatchResult<String, Void>> batchResultFuture =
                                    new AndroidFuture<>();

                    session.put(putDocumentsRequest, mExecutor, batchResultFuture::complete);
                            session.put(
                                    putDocumentsRequest, mExecutor, batchResultFuture::complete);
                            return batchResultFuture;
                        });
    }
@@ -152,10 +148,9 @@ public class FutureAppSearchSession implements Closeable {
     * of search provided.
     */
    public AndroidFuture<FutureSearchResults> search(
            @NonNull String queryExpression,
            @NonNull SearchSpec searchSpec) {
        return getSessionAsync().thenApply(
                        session -> session.search(queryExpression, searchSpec))
            @NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
        return getSessionAsync()
                .thenApply(session -> session.search(queryExpression, searchSpec))
                .thenApply(result -> new FutureSearchResults(result, mExecutor));
    }

@@ -173,8 +168,8 @@ public class FutureAppSearchSession implements Closeable {
        private final SearchResults mSearchResults;
        private final Executor mExecutor;

        public FutureSearchResults(@NonNull SearchResults searchResults,
                @NonNull Executor executor) {
        public FutureSearchResults(
                @NonNull SearchResults searchResults, @NonNull Executor executor) {
            mSearchResults = Objects.requireNonNull(searchResults);
            mExecutor = Objects.requireNonNull(executor);
        }
@@ -184,15 +179,14 @@ public class FutureAppSearchSession implements Closeable {
                    new AndroidFuture<>();

            mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
            return nextPageFuture.thenApply(result -> {
            return nextPageFuture.thenApply(
                    result -> {
                        if (result.isSuccess()) {
                            return result.getResultValue();
                        } else {
                    throw new RuntimeException(
                            failedResultToException(result));
                            throw new RuntimeException(failedResultToException(result));
                        }
                    });
        }

    }
}
+94 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.annotation.NonNull;
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.GlobalSearchSession;
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.observer.ObserverCallback;
import android.app.appsearch.observer.ObserverSpec;
import android.util.Slog;

import com.android.internal.infra.AndroidFuture;

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.Executor;

/** A wrapper around {@link GlobalSearchSession} that provides a future-based API. */
public class FutureGlobalSearchSession implements Closeable {
    private static final String TAG = FutureGlobalSearchSession.class.getSimpleName();
    private final Executor mExecutor;
    private final AndroidFuture<AppSearchResult<GlobalSearchSession>> mSettableSessionFuture;

    public FutureGlobalSearchSession(
            @NonNull AppSearchManager appSearchManager, @NonNull Executor executor) {
        this.mExecutor = executor;
        mSettableSessionFuture = new AndroidFuture<>();
        appSearchManager.createGlobalSearchSession(mExecutor, mSettableSessionFuture::complete);
    }

    private AndroidFuture<GlobalSearchSession> getSessionAsync() {
        return mSettableSessionFuture.thenApply(
                result -> {
                    if (result.isSuccess()) {
                        return result.getResultValue();
                    } else {
                        throw new RuntimeException(
                                FutureAppSearchSession.failedResultToException(result));
                    }
                });
    }

    /**
     * Registers an observer callback for the given target package name.
     *
     * @param targetPackageName The package name of the target app.
     * @param spec The observer spec.
     * @param executor The executor to run the observer callback on.
     * @param observer The observer callback to register.
     * @return A future that completes once the observer is registered.
     */
    public AndroidFuture<Void> registerObserverCallbackAsync(
            String targetPackageName,
            ObserverSpec spec,
            Executor executor,
            ObserverCallback observer) {
        return getSessionAsync()
                .thenCompose(
                        session -> {
                            try {
                                session.registerObserverCallback(
                                        targetPackageName, spec, executor, observer);
                                return AndroidFuture.completedFuture(null);
                            } catch (AppSearchException e) {
                                throw new RuntimeException(e);
                            }
                        });
    }

    @Override
    public void close() throws IOException {
        try {
            getSessionAsync().get().close();
        } catch (Exception ex) {
            Slog.e(TAG, "Failed to close global search session", ex);
        }
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.os.UserHandle;
 * services are properly unbound after the operation completes or a timeout occurs.
 *
 * @param <T> Class of wrapped service.
 * @hide
 */
public interface RemoteServiceCaller<T> {

+0 −1
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import java.util.function.Function;
 * Context#bindService}.
 *
 * @param <T> Class of wrapped service.
 * @hide
 */
public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> {
    private static final String TAG = "AppFunctionsServiceCall";
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ class FutureAppSearchSessionTest {
    fun clearData() {
        val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build()
        FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use {
            val setSchemaRequest = SetSchemaRequest.Builder().build()
            val setSchemaRequest = SetSchemaRequest.Builder().setForceOverride(true).build()
            it.setSchema(setSchemaRequest)
        }
    }
Loading