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

Commit 2b8c1eca authored by Alexander Dorokhine's avatar Alexander Dorokhine Committed by Android (Google) Code Review
Browse files

Merge "Update AppSearch code from Jetpack."

parents f2b1d840 1e6072d8
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