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

Commit 6a54e73a authored by Alexander Dorokhine's avatar Alexander Dorokhine
Browse files

Update Framework from Jetpack.

* e2124eb: Switch from throwing AssertionError to using a Truth assertion.
* 2ff6b81: Remove FutureUtils.map.
* 40eb8b5: Add projection to the SearchSpec.

Also, ports GlobalSearchSessionTest to platform for the first time.

Bug: 170997047
Bug: 162450968
Bug: 175661706
Bug: 170539682
Test: AppSearchSessionTest, GlobalSearchSessionTest
Change-Id: I9bdfb69b4d36b194c2c4038fb053f6237af9412a
parent fb182aeb
Loading
Loading
Loading
Loading
+31 −27
Original line number Diff line number Diff line
@@ -45,33 +45,35 @@ public class SearchResults implements Closeable {

    private final IAppSearchManager mService;

    // The database name to search over. If null, this will search over all database names.
    @Nullable
    private final String mDatabaseName;

    @UserIdInt
    private final int mUserId;

    private final String mQueryExpression;

    private final SearchSpec mSearchSpec;

    @UserIdInt
    private final int mUserId;

    private final Executor mExecutor;

    private long mNextPageToken;

    private boolean mIsFirstLoad = true;

    SearchResults(@NonNull IAppSearchManager service,
    SearchResults(
            @NonNull IAppSearchManager service,
            @Nullable String databaseName,
            @NonNull String queryExpression,
            @NonNull SearchSpec searchSpec,
            @UserIdInt int userId,
            @NonNull @CallbackExecutor Executor executor) {
        mService = Objects.requireNonNull(service);
        mUserId = userId;
        mDatabaseName = Objects.requireNonNull(databaseName);
        mDatabaseName = databaseName;
        mQueryExpression = Objects.requireNonNull(queryExpression);
        mSearchSpec = Objects.requireNonNull(searchSpec);
        mUserId = userId;
        mExecutor = Objects.requireNonNull(executor);
    }

@@ -90,11 +92,14 @@ public class SearchResults implements Closeable {
            if (mIsFirstLoad) {
                mIsFirstLoad = false;
                if (mDatabaseName == null) {
                    // Global query, there's no one package-database combination to check.
                    mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(), mUserId,
                            wrapCallback(callback));
                } else {
                    mService.query(mDatabaseName, mQueryExpression, mSearchSpec.getBundle(),
                            mUserId, wrapCallback(callback));
                    // Normal local query, pass in specified database.
                    mService.query(
                            mDatabaseName, mQueryExpression, mSearchSpec.getBundle(), mUserId,
                            wrapCallback(callback));
                }
            } else {
                mService.getNextPage(mNextPageToken, mUserId, wrapCallback(callback));
@@ -104,31 +109,13 @@ public class SearchResults implements Closeable {
        }
    }

    private void invokeCallback(AppSearchResult result,
            @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
        if (result.isSuccess()) {
            try {
                SearchResultPage searchResultPage =
                        new SearchResultPage((Bundle) result.getResultValue());
                mNextPageToken = searchResultPage.getNextPageToken();
                callback.accept(AppSearchResult.newSuccessfulResult(
                        searchResultPage.getResults()));
            } catch (Throwable t) {
                callback.accept(AppSearchResult.throwableToFailedResult(t));
            }
        } else {
            callback.accept(result);
        }
    }
    @Override
    public void close() {
        mExecutor.execute(() -> {
        try {
            mService.invalidateNextPageToken(mNextPageToken, mUserId);
        } catch (RemoteException e) {
            Log.d(TAG, "Unable to close the SearchResults", e);
        }
        });
    }

    private IAppSearchResultCallback wrapCallback(
@@ -139,4 +126,21 @@ public class SearchResults implements Closeable {
            }
        };
    }

    private void invokeCallback(AppSearchResult result,
            @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
        if (result.isSuccess()) {
            try {
                SearchResultPage searchResultPage =
                        new SearchResultPage((Bundle) result.getResultValue());
                mNextPageToken = searchResultPage.getNextPageToken();
                callback.accept(AppSearchResult.newSuccessfulResult(
                        searchResultPage.getResults()));
            } catch (Throwable t) {
                callback.accept(AppSearchResult.throwableToFailedResult(t));
            }
        } else {
            callback.accept(result);
        }
    }
}
+140 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.SuppressLint;
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.exceptions.IllegalSearchSpecException;
import android.os.Bundle;
import android.util.ArrayMap;

import com.android.internal.util.Preconditions;

@@ -33,6 +34,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * This class represents the specification logic for AppSearch. It can be used to set the type of
@@ -40,6 +43,15 @@ import java.util.List;
 */
// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
public final class SearchSpec {
    /**
     * Schema type to be used in {@link SearchSpec.Builder#addProjectionTypePropertyPath} to apply
     * property paths to all results, excepting any types that have had their own, specific property
     * paths set.
     *
     * @hide
     */
    public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";

    static final String TERM_MATCH_TYPE_FIELD = "termMatchType";
    static final String SCHEMA_TYPE_FIELD = "schemaType";
    static final String NAMESPACE_FIELD = "namespace";
@@ -49,6 +61,7 @@ public final class SearchSpec {
    static final String SNIPPET_COUNT_FIELD = "snippetCount";
    static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
    static final String MAX_SNIPPET_FIELD = "maxSnippet";
    static final String PROJECTION_TYPE_PROPERTY_PATHS_FIELD = "projectionTypeFieldMasks";

    /** @hide */
    public static final int DEFAULT_NUM_PER_PAGE = 10;
@@ -206,12 +219,35 @@ public final class SearchSpec {
        return mBundle.getInt(MAX_SNIPPET_FIELD);
    }

    /**
     * Returns a map from schema type to property paths to be used for projection.
     *
     * <p>If the map is empty, then all properties will be retrieved for all results.
     *
     * <p>Calling this function repeatedly is inefficient. Prefer to retain the Map returned by this
     * function, rather than calling it multiple times.
     *
     * @hide
     */
    @NonNull
    public Map<String, List<String>> getProjectionTypePropertyPaths() {
        Bundle typePropertyPathsBundle = mBundle.getBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD);
        Set<String> schemaTypes = typePropertyPathsBundle.keySet();
        Map<String, List<String>> typePropertyPathsMap = new ArrayMap<>(schemaTypes.size());
        for (String schemaType : schemaTypes) {
            typePropertyPathsMap.put(
                    schemaType, typePropertyPathsBundle.getStringArrayList(schemaType));
        }
        return typePropertyPathsMap;
    }

    /** Builder for {@link SearchSpec objects}. */
    public static final class Builder {

        private final Bundle mBundle;
        private final ArrayList<String> mSchemaTypes = new ArrayList<>();
        private final ArrayList<String> mNamespaces = new ArrayList<>();
        private final Bundle mProjectionTypePropertyMasks = new Bundle();
        private boolean mBuilt = false;

        /** Creates a new {@link SearchSpec.Builder}. */
@@ -385,6 +421,109 @@ public final class SearchSpec {
            return this;
        }

        /**
         * Adds property paths for the specified type to be used for projection. If property paths
         * are added for a type, then only the properties referred to will be retrieved for results
         * of that type. If a property path that is specified isn't present in a result, it will be
         * ignored for that result. Property paths cannot be null.
         *
         * <p>If no property paths are added for a particular type, then all properties of results
         * of that type will be retrieved.
         *
         * <p>If property path is added for the {@link SearchSpec#PROJECTION_SCHEMA_TYPE_WILDCARD},
         * then those property paths will apply to all results, excepting any types that have their
         * own, specific property paths set.
         *
         * <p>Suppose the following document is in the index.
         *
         * <pre>{@code
         * Email: Document {
         *   sender: Document {
         *     name: "Mr. Person"
         *     email: "mrperson123@google.com"
         *   }
         *   recipients: [
         *     Document {
         *       name: "John Doe"
         *       email: "johndoe123@google.com"
         *     }
         *     Document {
         *       name: "Jane Doe"
         *       email: "janedoe123@google.com"
         *     }
         *   ]
         *   subject: "IMPORTANT"
         *   body: "Limited time offer!"
         * }
         * }</pre>
         *
         * <p>Then, suppose that a query for "important" is issued with the following projection
         * type property paths:
         *
         * <pre>{@code
         * {schemaType: "Email", ["subject", "sender.name", "recipients.name"]}
         * }</pre>
         *
         * <p>The above document will be returned as:
         *
         * <pre>{@code
         * Email: Document {
         *   sender: Document {
         *     name: "Mr. Body"
         *   }
         *   recipients: [
         *     Document {
         *       name: "John Doe"
         *     }
         *     Document {
         *       name: "Jane Doe"
         *     }
         *   ]
         *   subject: "IMPORTANT"
         * }
         * }</pre>
         *
         * @hide
         */
        @NonNull
        public SearchSpec.Builder addProjectionTypePropertyPaths(
                @NonNull String schemaType, @NonNull String... propertyPaths) {
            Preconditions.checkNotNull(propertyPaths);
            return addProjectionTypePropertyPaths(schemaType, Arrays.asList(propertyPaths));
        }

        /**
         * Adds property paths for the specified type to be used for projection. If property paths
         * are added for a type, then only the properties referred to will be retrieved for results
         * of that type. If a property path that is specified isn't present in a result, it will be
         * ignored for that result. Property paths cannot be null.
         *
         * <p>If no property paths are added for a particular type, then all properties of results
         * of that type will be retrieved.
         *
         * <p>If property path is added for the {@link SearchSpec#PROJECTION_SCHEMA_TYPE_WILDCARD},
         * then those property paths will apply to all results, excepting any types that have their
         * own, specific property paths set.
         *
         * <p>{@see SearchSpec.Builder#addProjectionTypePropertyPath(String, String...)}
         *
         * @hide
         */
        @NonNull
        public SearchSpec.Builder addProjectionTypePropertyPaths(
                @NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
            Preconditions.checkState(!mBuilt, "Builder has already been used");
            Preconditions.checkNotNull(schemaType);
            Preconditions.checkNotNull(propertyPaths);
            ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
            for (String propertyPath : propertyPaths) {
                Preconditions.checkNotNull(propertyPath);
                propertyPathsArrayList.add(propertyPath);
            }
            mProjectionTypePropertyMasks.putStringArrayList(schemaType, propertyPathsArrayList);
            return this;
        }

        /**
         * Constructs a new {@link SearchSpec} from the contents of this builder.
         *
@@ -398,6 +537,7 @@ public final class SearchSpec {
            }
            mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
            mBundle.putStringArrayList(SCHEMA_TYPE_FIELD, mSchemaTypes);
            mBundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks);
            mBuilt = true;
            return new SearchSpec(mBundle);
        }
+1 −1
Original line number Diff line number Diff line
I0577839bfddf95a555399df441d317b00c7c7c48
Idd770a064edfeb6dc648571fc6706c087b8e605a
+3 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.GlobalSearchSession;
import android.app.appsearch.GlobalSearchSessionShim;
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchResultsShim;
import android.app.appsearch.SearchSpec;
@@ -40,7 +41,7 @@ import java.util.concurrent.Executors;
 * a consistent interface.
 * @hide
 */
public class GlobalSearchSessionShimImpl {
public class GlobalSearchSessionShimImpl implements GlobalSearchSessionShim {
    private final GlobalSearchSession mGlobalSearchSession;
    private final ExecutorService mExecutor;

@@ -64,6 +65,7 @@ public class GlobalSearchSessionShimImpl {
    }

    @NonNull
    @Override
    public SearchResultsShim query(
            @NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
        SearchResults searchResults =
+4 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.appsearch.testing;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;

import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchSessionShim;
@@ -25,8 +26,6 @@ import android.app.appsearch.GetByUriRequest;
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultsShim;

import junit.framework.AssertionFailedError;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
@@ -36,9 +35,9 @@ public class AppSearchTestUtils {
    public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
            Future<AppSearchBatchResult<K, V>> future) throws Exception {
        AppSearchBatchResult<K, V> result = future.get();
        if (!result.isSuccess()) {
            throw new AssertionFailedError("AppSearchBatchResult not successful: " + result);
        }
        assertWithMessage("AppSearchBatchResult not successful: " + result)
                .that(result.isSuccess())
                .isTrue();
        return result;
    }

Loading