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

Commit 1e6072d8 authored by Alexander Dorokhine's avatar Alexander Dorokhine
Browse files

Update AppSearch code from Jetpack.

* 31db05: Move visibility settings into SetSchemaRequest.
* af6646: Support retrieving the current database's schema.
* 468ec2: Minor comment fix.
* b67963: Refactor AppSearchImpl to use List instead of Set.
* 1ae2bc: Delete an assertion that bundle.equals(bundle).

Bug: 169883602
Bug: 172260083
Bug: 162450968
Bug: 174825775
Test: Presubmit
Change-Id: I485bc9d1d9980467f6bdde1f36b077c0a3e7f5b4
parent 44b040f5
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -224,7 +224,11 @@ public class AppSearchManager {
        }
        AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
        try {
            mService.setSchema(DEFAULT_DATABASE_NAME, schemaBundles, request.isForceOverride(),
            mService.setSchema(
                    DEFAULT_DATABASE_NAME,
                    schemaBundles,
                    new ArrayList<>(request.getSchemasNotPlatformSurfaceable()),
                    request.isForceOverride(),
                    new IAppSearchResultCallback.Stub() {
                        public void onResult(AppSearchResult result) {
                            future.complete(result);
+50 −6
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.appsearch.exceptions.IllegalSchemaException;
import android.app.appsearch.util.BundleUtil;
import android.os.Bundle;
import android.util.ArraySet;

@@ -31,6 +32,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
@@ -40,7 +42,7 @@ import java.util.Set;
 *
 * <p>The schema consists of type information, properties, and config (like tokenization type).
 *
 * @see AppSearchManager#setSchema
 * @see AppSearchSession#setSchema
 */
public final class AppSearchSchema {
    private static final String SCHEMA_TYPE_FIELD = "schemaType";
@@ -94,17 +96,37 @@ public final class AppSearchSchema {
        return ret;
    }

    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof AppSearchSchema)) {
            return false;
        }
        AppSearchSchema otherSchema = (AppSearchSchema) other;
        if (!getSchemaType().equals(otherSchema.getSchemaType())) {
            return false;
        }
        return getProperties().equals(otherSchema.getProperties());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getSchemaType(), getProperties());
    }

    /** Builder for {@link AppSearchSchema objects}. */
    public static final class Builder {
        private final String mTypeName;
        private final String mSchemaType;
        private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
        private final Set<String> mPropertyNames = new ArraySet<>();
        private boolean mBuilt = false;

        /** Creates a new {@link AppSearchSchema.Builder}. */
        public Builder(@NonNull String typeName) {
            Preconditions.checkNotNull(typeName);
            mTypeName = typeName;
        public Builder(@NonNull String schemaType) {
            Preconditions.checkNotNull(schemaType);
            mSchemaType = schemaType;
        }

        /** Adds a property to the given type. */
@@ -133,7 +155,7 @@ public final class AppSearchSchema {
        public AppSearchSchema build() {
            Preconditions.checkState(!mBuilt, "Builder has already been used");
            Bundle bundle = new Bundle();
            bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mTypeName);
            bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mSchemaType);
            bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
            mBuilt = true;
            return new AppSearchSchema(bundle);
@@ -279,6 +301,8 @@ public final class AppSearchSchema {

        final Bundle mBundle;

        @Nullable private Integer mHashCode;

        PropertyConfig(@NonNull Bundle bundle) {
            mBundle = Preconditions.checkNotNull(bundle);
        }
@@ -327,6 +351,26 @@ public final class AppSearchSchema {
            return mBundle.getInt(TOKENIZER_TYPE_FIELD);
        }

        @Override
        public boolean equals(@Nullable Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof PropertyConfig)) {
                return false;
            }
            PropertyConfig otherProperty = (PropertyConfig) other;
            return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
        }

        @Override
        public int hashCode() {
            if (mHashCode == null) {
                mHashCode = BundleUtil.deepHashCode(mBundle);
            }
            return mHashCode;
        }

        /**
         * Builder for {@link PropertyConfig}.
         *
+5 −1
Original line number Diff line number Diff line
@@ -140,7 +140,11 @@ public final class AppSearchSession {
            schemaBundles.add(schema.getBundle());
        }
        try {
            mService.setSchema(mDatabaseName, schemaBundles, request.isForceOverride(),
            mService.setSchema(
                    mDatabaseName,
                    schemaBundles,
                    new ArrayList<>(request.getSchemasNotPlatformSurfaceable()),
                    request.isForceOverride(),
                    new IAppSearchResultCallback.Stub() {
                        public void onResult(AppSearchResult result) {
                            executor.execute(() -> callback.accept(result));
+10 −136
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ 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;

@@ -37,12 +38,12 @@ import java.util.Set;
 *
 * <p>Documents are constructed via {@link GenericDocument.Builder}.
 *
 * @see AppSearchManager#putDocuments
 * @see AppSearchManager#getByUri
 * @see AppSearchManager#query
 * @see AppSearchSession#putDocuments
 * @see AppSearchSession#getByUri
 * @see AppSearchSession#query
 */
public class GenericDocument {
    private static final String TAG = "GenericDocument";
    private static final String TAG = "AppSearchGenericDocumen";

    /** The default empty namespace. */
    public static final String DEFAULT_NAMESPACE = "";
@@ -462,144 +463,17 @@ public class GenericDocument {
            return false;
        }
        GenericDocument otherDocument = (GenericDocument) other;
        return bundleEquals(this.mBundle, otherDocument.mBundle);
    }

    /**
     * Deeply checks whether two bundles are equal.
     *
     * <p>Two bundles will be considered equal if they contain the same content.
     */
    @SuppressWarnings("unchecked")
    private static boolean bundleEquals(Bundle one, Bundle two) {
        if (one.size() != two.size()) {
            return false;
        }
        Set<String> keySetOne = one.keySet();
        Object valueOne;
        Object valueTwo;
        // Bundle inherit its equals() from Object.java, which only compare their memory address.
        // We should iterate all keys and check their presents and values in both bundle.
        for (String key : keySetOne) {
            valueOne = one.get(key);
            valueTwo = two.get(key);
            if (valueOne instanceof Bundle
                    && valueTwo instanceof Bundle
                    && !bundleEquals((Bundle) valueOne, (Bundle) valueTwo)) {
                return false;
            } else if (valueOne == null && (valueTwo != null || !two.containsKey(key))) {
                // If we call bundle.get(key) when the 'key' doesn't actually exist in the
                // bundle, we'll get back a null. So make sure that both values are null and
                // both keys exist in the bundle.
                return false;
            } else if (valueOne instanceof boolean[]) {
                if (!(valueTwo instanceof boolean[])
                        || !Arrays.equals((boolean[]) valueOne, (boolean[]) valueTwo)) {
                    return false;
                }
            } else if (valueOne instanceof long[]) {
                if (!(valueTwo instanceof long[])
                        || !Arrays.equals((long[]) valueOne, (long[]) valueTwo)) {
                    return false;
                }
            } else if (valueOne instanceof double[]) {
                if (!(valueTwo instanceof double[])
                        || !Arrays.equals((double[]) valueOne, (double[]) valueTwo)) {
                    return false;
                }
            } else if (valueOne instanceof Bundle[]) {
                if (!(valueTwo instanceof Bundle[])) {
                    return false;
                }
                Bundle[] bundlesOne = (Bundle[]) valueOne;
                Bundle[] bundlesTwo = (Bundle[]) valueTwo;
                if (bundlesOne.length != bundlesTwo.length) {
                    return false;
                }
                for (int i = 0; i < bundlesOne.length; i++) {
                    if (!bundleEquals(bundlesOne[i], bundlesTwo[i])) {
                        return false;
                    }
                }
            } else if (valueOne instanceof ArrayList) {
                if (!(valueTwo instanceof ArrayList)) {
                    return false;
                }
                ArrayList<Bundle> bundlesOne = (ArrayList<Bundle>) valueOne;
                ArrayList<Bundle> bundlesTwo = (ArrayList<Bundle>) valueTwo;
                if (bundlesOne.size() != bundlesTwo.size()) {
                    return false;
                }
                for (int i = 0; i < bundlesOne.size(); i++) {
                    if (!bundleEquals(bundlesOne.get(i), bundlesTwo.get(i))) {
                        return false;
                    }
                }
            } else if (valueOne instanceof Object[]) {
                if (!(valueTwo instanceof Object[])
                        || !Arrays.equals((Object[]) valueOne, (Object[]) valueTwo)) {
                    return false;
                }
            }
        }
        return true;
        return BundleUtil.deepEquals(this.mBundle, otherDocument.mBundle);
    }

    @Override
    public int hashCode() {
        if (mHashCode == null) {
            mHashCode = bundleHashCode(mBundle);
            mHashCode = BundleUtil.deepHashCode(mBundle);
        }
        return mHashCode;
    }

    /**
     * Calculates the hash code for a bundle.
     *
     * <p>The hash code is only effected by the contents in the bundle. Bundles will get consistent
     * hash code if they have same contents.
     */
    @SuppressWarnings("unchecked")
    private static int bundleHashCode(Bundle bundle) {
        int[] hashCodes = new int[bundle.size()];
        int i = 0;
        // Bundle inherit its hashCode() from Object.java, which only relative to their memory
        // address. Bundle doesn't have an order, so we should iterate all keys and combine
        // their value's hashcode into an array. And use the hashcode of the array to be
        // the hashcode of the bundle.
        for (String key : bundle.keySet()) {
            Object value = bundle.get(key);
            if (value instanceof boolean[]) {
                hashCodes[i++] = Arrays.hashCode((boolean[]) value);
            } else if (value instanceof long[]) {
                hashCodes[i++] = Arrays.hashCode((long[]) value);
            } else if (value instanceof double[]) {
                hashCodes[i++] = Arrays.hashCode((double[]) value);
            } else if (value instanceof String[]) {
                hashCodes[i++] = Arrays.hashCode((Object[]) value);
            } else if (value instanceof Bundle) {
                hashCodes[i++] = bundleHashCode((Bundle) value);
            } else if (value instanceof Bundle[]) {
                Bundle[] bundles = (Bundle[]) value;
                int[] innerHashCodes = new int[bundles.length];
                for (int j = 0; j < innerHashCodes.length; j++) {
                    innerHashCodes[j] = bundleHashCode(bundles[j]);
                }
                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
            } else if (value instanceof ArrayList) {
                ArrayList<Bundle> bundles = (ArrayList<Bundle>) value;
                int[] innerHashCodes = new int[bundles.size()];
                for (int j = 0; j < innerHashCodes.length; j++) {
                    innerHashCodes[j] = bundleHashCode(bundles.get(j));
                }
                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
            } else {
                hashCodes[i++] = value.hashCode();
            }
        }
        return Arrays.hashCode(hashCodes);
    }

    @Override
    @NonNull
    public String toString() {
@@ -683,10 +557,10 @@ public class GenericDocument {
         *
         * @param uri The uri of {@link GenericDocument}.
         * @param schemaType The schema type of the {@link GenericDocument}. The passed-in {@code
         *     schemaType} must be defined using {@link AppSearchManager#setSchema} prior to
         *     schemaType} must be defined using {@link AppSearchSession#setSchema} prior to
         *     inserting a document of this {@code schemaType} into the AppSearch index using {@link
         *     AppSearchManager#putDocuments}. Otherwise, the document will be rejected by {@link
         *     AppSearchManager#putDocuments}.
         *     AppSearchSession#putDocuments}. Otherwise, the document will be rejected by {@link
         *     AppSearchSession#putDocuments}.
         */
        @SuppressWarnings("unchecked")
        public Builder(@NonNull String uri, @NonNull String schemaType) {
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ import java.util.Set;
/**
 * Encapsulates a request to retrieve documents by namespace and URI.
 *
 * @see AppSearchManager#getByUri
 * @see AppSearchSession#getByUri
 */
public final class GetByUriRequest {
    private final String mNamespace;
Loading