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

Commit 51193cd9 authored by Alexander Dorokhine's avatar Alexander Dorokhine
Browse files

Sync Framework from Jetpack.

Included changes:
* ebd84f: Further fixes and improvements to export script.
* 968bbd: Copy AppSearchSession, GlobalSearchSession and SearchResults into shims.
* a0d314: Refactor tests involving AppSearchSession into base and concrete class.
* 8d652e: Remove spam logs from GenericDocument.
* 11e8f8: Update AppSearch to be in sync google3 update aosp/1541514.
* cdd6f7: Add package name to SearchResult.

Bug: 176519441
Bug: 175801531
Bug: 174614009
Bug: 169883602
Test: Presubmit
Change-Id: I4cf2d830294b41909b6d41adb7925ddebc1d01eb
parent 097aef6f
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.util.BundleUtil;
import android.os.Bundle;
import android.util.Log;
@@ -92,9 +91,7 @@ public class GenericDocument {
    /** Contains {@link GenericDocument} basic information (uri, schemaType etc). */
    @NonNull final Bundle mBundle;

    /**
     * Contains all properties in {@link GenericDocument} to support getting properties via keys.
     */
    /** Contains all properties in {@link GenericDocument} to support getting properties via keys */
    @NonNull private final Bundle mProperties;

    @NonNull private final String mUri;
@@ -201,6 +198,25 @@ public class GenericDocument {
        return Collections.unmodifiableSet(mProperties.keySet());
    }

    /**
     * Retrieves the property value with the given key as {@link Object}.
     *
     * @param key The key to look for.
     * @return The entry with the given key as an object or {@code null} if there is no such key.
     * @hide
     */
    @Nullable
    public Object getProperty(@NonNull String key) {
        Preconditions.checkNotNull(key);
        Object property = mProperties.get(key);
        if (property instanceof ArrayList) {
            return getPropertyBytesArray(key);
        } else if (property instanceof Bundle[]) {
            return getPropertyDocumentArray(key);
        }
        return property;
    }

    /**
     * Retrieves a {@link String} value by key.
     *
+0 −1
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.app.appsearch;

import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.appsearch.exceptions.AppSearchException;

import com.android.internal.util.Preconditions;

+22 −18
Original line number Diff line number Diff line
@@ -49,31 +49,20 @@ public final class SearchResult {
    /** @hide */
    public static final String MATCHES_FIELD = "matches";

    @NonNull private final Bundle mBundle;
    /** @hide */
    public static final String PACKAGE_NAME_FIELD = "packageName";

    @NonNull private final Bundle mDocumentBundle;
    @NonNull private final Bundle mBundle;

    /** Cache of the inflated document. Comes from inflating mDocumentBundle at first use. */
    @Nullable private GenericDocument mDocument;

    /**
     * Contains a list of MatchInfo bundles that matched the request.
     *
     * <p>Only populated when requested in both {@link SearchSpec.Builder#setSnippetCount} and
     * {@link SearchSpec.Builder#setSnippetCountPerProperty}.
     *
     * @see #getMatches()
     */
    @NonNull private final List<Bundle> mMatchBundles;

    /** Cache of the inflated matches. Comes from inflating mMatchBundles at first use. */
    @Nullable private List<MatchInfo> mMatches;

    /** @hide */
    public SearchResult(@NonNull Bundle bundle) {
        mBundle = Preconditions.checkNotNull(bundle);
        mDocumentBundle = Preconditions.checkNotNull(bundle.getBundle(DOCUMENT_FIELD));
        mMatchBundles = Preconditions.checkNotNull(bundle.getParcelableArrayList(MATCHES_FIELD));
    }

    /** @hide */
@@ -90,7 +79,9 @@ public final class SearchResult {
    @NonNull
    public GenericDocument getDocument() {
        if (mDocument == null) {
            mDocument = new GenericDocument(mDocumentBundle);
            mDocument =
                    new GenericDocument(
                            Preconditions.checkNotNull(mBundle.getBundle(DOCUMENT_FIELD)));
        }
        return mDocument;
    }
@@ -106,15 +97,28 @@ public final class SearchResult {
    @NonNull
    public List<MatchInfo> getMatches() {
        if (mMatches == null) {
            mMatches = new ArrayList<>(mMatchBundles.size());
            for (int i = 0; i < mMatchBundles.size(); i++) {
                MatchInfo matchInfo = new MatchInfo(getDocument(), mMatchBundles.get(i));
            List<Bundle> matchBundles =
                    Preconditions.checkNotNull(mBundle.getParcelableArrayList(MATCHES_FIELD));
            mMatches = new ArrayList<>(matchBundles.size());
            for (int i = 0; i < matchBundles.size(); i++) {
                MatchInfo matchInfo = new MatchInfo(getDocument(), matchBundles.get(i));
                mMatches.add(matchInfo);
            }
        }
        return mMatches;
    }

    /**
     * Contains the package name that stored the {@link GenericDocument}.
     *
     * @return Package name that stored the document
     * @hide
     */
    @NonNull
    public String getPackageName() {
        return Preconditions.checkNotNull(mBundle.getString(PACKAGE_NAME_FIELD));
    }

    /**
     * This class represents a match objects for any Snippets that might be present in {@link
     * SearchResults} from query. Using this class user can get the full text, exact matches and
+0 −2
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package android.app.appsearch;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.exceptions.IllegalSearchSpecException;
import android.os.Bundle;
import android.util.ArrayMap;
+65 −15
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.server.appsearch.external.localstorage.converter.SearchResult
import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;

import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
import com.google.android.icing.proto.DeleteResultProto;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.GetAllNamespacesResultProto;
@@ -609,7 +610,7 @@ public final class AppSearchImpl {
        SearchSpecProto searchSpecProto = SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
        SearchSpecProto.Builder searchSpecBuilder =
                searchSpecProto.toBuilder().setQuery(queryExpression);
        DeleteResultProto deleteResultProto;
        DeleteByQueryResultProto deleteResultProto;
        mReadWriteLock.writeLock().lock();
        try {
            // Only rewrite SearchSpec for non empty prefixes.
@@ -797,11 +798,27 @@ public final class AppSearchImpl {
     * Removes any prefixes from types and namespaces mentioned anywhere in {@code documentBuilder}.
     *
     * @param documentBuilder The document to mutate
     * @return Prefix name that was removed from the document.
     * @throws AppSearchException if there are unexpected database prefixing errors.
     */
    @NonNull
    @VisibleForTesting
    static void removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
    static String removePrefixesFromDocument(@NonNull DocumentProto.Builder documentBuilder)
            throws AppSearchException {
        // Rewrite the type name and namespace to remove the prefix.
        String schemaPrefix = getPrefix(documentBuilder.getSchema());
        String namespacePrefix = getPrefix(documentBuilder.getNamespace());

        if (!schemaPrefix.equals(namespacePrefix)) {
            throw new AppSearchException(
                    AppSearchResult.RESULT_INTERNAL_ERROR,
                    "Found unexpected"
                            + " multiple prefix names in document: "
                            + schemaPrefix
                            + ", "
                            + namespacePrefix);
        }

        documentBuilder.setSchema(removePrefix(documentBuilder.getSchema()));
        documentBuilder.setNamespace(removePrefix(documentBuilder.getNamespace()));

@@ -816,12 +833,22 @@ public final class AppSearchImpl {
                for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
                    DocumentProto.Builder derivedDocumentBuilder =
                            propertyBuilder.getDocumentValues(documentIdx).toBuilder();
                    removePrefixesFromDocument(derivedDocumentBuilder);
                    String nestedPrefix = removePrefixesFromDocument(derivedDocumentBuilder);
                    if (!nestedPrefix.equals(schemaPrefix)) {
                        throw new AppSearchException(
                                AppSearchResult.RESULT_INTERNAL_ERROR,
                                "Found unexpected multiple prefix names in document: "
                                        + schemaPrefix
                                        + ", "
                                        + nestedPrefix);
                    }
                    propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
                }
                documentBuilder.setProperties(propertyIdx, propertyBuilder);
            }
        }

        return schemaPrefix;
    }

    /**
@@ -929,6 +956,25 @@ public final class AppSearchImpl {
        return packageName + PACKAGE_DELIMITER + databaseName + DATABASE_DELIMITER;
    }

    /**
     * Returns the package name that's contained within the {@code prefix}.
     *
     * @param prefix Prefix string that contains the package name inside of it. The package name
     *     must be in the front of the string, and separated from the rest of the string by the
     *     {@link #PACKAGE_DELIMITER}.
     * @return Valid package name.
     */
    @NonNull
    private static String getPackageName(@NonNull String prefix) {
        int delimiterIndex = prefix.indexOf(PACKAGE_DELIMITER);
        if (delimiterIndex == -1) {
            // This should never happen if we construct our prefixes properly
            Log.wtf(TAG, "Malformed prefix doesn't contain package name: " + prefix);
            return "";
        }
        return prefix.substring(0, delimiterIndex);
    }

    @NonNull
    private static String removePrefix(@NonNull String prefixedString) throws AppSearchException {
        // The prefix is made up of the package, then the database. So we only need to find the
@@ -949,7 +995,7 @@ public final class AppSearchImpl {
        if (databaseDelimiterIndex == -1) {
            throw new AppSearchException(
                    AppSearchResult.RESULT_UNKNOWN_ERROR,
                    "The databaseName prefixed value doesn't contains a valid database name.");
                    "The databaseName prefixed value doesn't contain a valid database name.");
        }

        // Add 1 to include the char size of the DATABASE_DELIMITER
@@ -1034,20 +1080,24 @@ public final class AppSearchImpl {
    }

    /** Remove the rewritten schema types from any result documents. */
    private static SearchResultPage rewriteSearchResultProto(
            @NonNull SearchResultProto searchResultProto) throws AppSearchException {
    @NonNull
    @VisibleForTesting
    static SearchResultPage rewriteSearchResultProto(@NonNull SearchResultProto searchResultProto)
            throws AppSearchException {
        // Parallel array of package names for each document search result.
        List<String> packageNames = new ArrayList<>(searchResultProto.getResultsCount());

        SearchResultProto.Builder resultsBuilder = searchResultProto.toBuilder();
        for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
            if (searchResultProto.getResults(i).hasDocument()) {
            SearchResultProto.ResultProto.Builder resultBuilder =
                    searchResultProto.getResults(i).toBuilder();
            DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
                removePrefixesFromDocument(documentBuilder);
            String prefix = removePrefixesFromDocument(documentBuilder);
            packageNames.add(getPackageName(prefix));
            resultBuilder.setDocument(documentBuilder);
            resultsBuilder.setResults(i, resultBuilder);
        }
        }
        return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder);
        return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder, packageNames);
    }

    @GuardedBy("mReadWriteLock")
Loading