All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.app.appsearch.util.BundleUtil Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright 2020 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 android.app.appsearch.util;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Parcel;
import android.util.SparseArray;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * Utilities for working with {@link android.os.Bundle}.
 *
 * @hide
 */
public final class BundleUtil {
    private BundleUtil() {}

    /**
     * Deeply checks two bundles are equal or not.
     *
     * 

Two bundles will be considered equal if they contain the same keys, and each value is also * equal. Bundle values are compared using deepEquals. */ public static boolean deepEquals(@Nullable Bundle one, @Nullable Bundle two) { if (one == null && two == null) { return true; } if (one == null || two == null) { return false; } if (one.size() != two.size()) { return false; } if (!one.keySet().equals(two.keySet())) { return false; } // 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 : one.keySet()) { if (!bundleValueEquals(one.get(key), two.get(key))) { return false; } } return true; } /** * Deeply checks whether two values in a Bundle are equal or not. * *

Values of type Bundle are compared using {@link #deepEquals}. */ private static boolean bundleValueEquals(@Nullable Object one, @Nullable Object two) { if (one == null && two == null) { return true; } if (one == null || two == null) { return false; } if (one.equals(two)) { return true; } if (one instanceof Bundle && two instanceof Bundle) { return deepEquals((Bundle) one, (Bundle) two); } else if (one instanceof int[] && two instanceof int[]) { return Arrays.equals((int[]) one, (int[]) two); } else if (one instanceof byte[] && two instanceof byte[]) { return Arrays.equals((byte[]) one, (byte[]) two); } else if (one instanceof char[] && two instanceof char[]) { return Arrays.equals((char[]) one, (char[]) two); } else if (one instanceof long[] && two instanceof long[]) { return Arrays.equals((long[]) one, (long[]) two); } else if (one instanceof float[] && two instanceof float[]) { return Arrays.equals((float[]) one, (float[]) two); } else if (one instanceof short[] && two instanceof short[]) { return Arrays.equals((short[]) one, (short[]) two); } else if (one instanceof double[] && two instanceof double[]) { return Arrays.equals((double[]) one, (double[]) two); } else if (one instanceof boolean[] && two instanceof boolean[]) { return Arrays.equals((boolean[]) one, (boolean[]) two); } else if (one instanceof Object[] && two instanceof Object[]) { Object[] arrayOne = (Object[]) one; Object[] arrayTwo = (Object[]) two; if (arrayOne.length != arrayTwo.length) { return false; } if (Arrays.equals(arrayOne, arrayTwo)) { return true; } for (int i = 0; i < arrayOne.length; i++) { if (!bundleValueEquals(arrayOne[i], arrayTwo[i])) { return false; } } return true; } else if (one instanceof ArrayList && two instanceof ArrayList) { ArrayList listOne = (ArrayList) one; ArrayList listTwo = (ArrayList) two; if (listOne.size() != listTwo.size()) { return false; } for (int i = 0; i < listOne.size(); i++) { if (!bundleValueEquals(listOne.get(i), listTwo.get(i))) { return false; } } return true; } else if (one instanceof SparseArray && two instanceof SparseArray) { SparseArray arrayOne = (SparseArray) one; SparseArray arrayTwo = (SparseArray) two; if (arrayOne.size() != arrayTwo.size()) { return false; } for (int i = 0; i < arrayOne.size(); i++) { if (arrayOne.keyAt(i) != arrayTwo.keyAt(i) || !bundleValueEquals(arrayOne.valueAt(i), arrayTwo.valueAt(i))) { return false; } } return true; } return false; } /** * Calculates the hash code for a bundle. * *

The hash code is only effected by the contents in the bundle. Bundles will get consistent * hash code if they have same contents. */ public static int deepHashCode(@Nullable Bundle bundle) { if (bundle == null) { return 0; } int[] hashCodes = new int[bundle.size() + 1]; int hashCodeIdx = 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. // Because bundle.keySet() doesn't guarantee any particular order, we need to sort the keys // in case the iteration order varies from run to run. String[] keys = bundle.keySet().toArray(new String[0]); Arrays.sort(keys); // Hash the keys so we can detect key-only differences hashCodes[hashCodeIdx++] = Arrays.hashCode(keys); for (int keyIdx = 0; keyIdx < keys.length; keyIdx++) { Object value = bundle.get(keys[keyIdx]); if (value instanceof Bundle) { hashCodes[hashCodeIdx++] = deepHashCode((Bundle) value); } else if (value instanceof int[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((int[]) value); } else if (value instanceof byte[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((byte[]) value); } else if (value instanceof char[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((char[]) value); } else if (value instanceof long[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((long[]) value); } else if (value instanceof float[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((float[]) value); } else if (value instanceof short[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((short[]) value); } else if (value instanceof double[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((double[]) value); } else if (value instanceof boolean[]) { hashCodes[hashCodeIdx++] = Arrays.hashCode((boolean[]) value); } else if (value instanceof String[]) { // Optimization to avoid Object[] handler creating an inner array for common cases hashCodes[hashCodeIdx++] = Arrays.hashCode((String[]) value); } else if (value instanceof Object[]) { Object[] array = (Object[]) value; int[] innerHashCodes = new int[array.length]; for (int j = 0; j < array.length; j++) { if (array[j] instanceof Bundle) { innerHashCodes[j] = deepHashCode((Bundle) array[j]); } else if (array[j] != null) { innerHashCodes[j] = array[j].hashCode(); } } hashCodes[hashCodeIdx++] = Arrays.hashCode(innerHashCodes); } else if (value instanceof ArrayList) { ArrayList list = (ArrayList) value; int[] innerHashCodes = new int[list.size()]; for (int j = 0; j < innerHashCodes.length; j++) { Object item = list.get(j); if (item instanceof Bundle) { innerHashCodes[j] = deepHashCode((Bundle) item); } else if (item != null) { innerHashCodes[j] = item.hashCode(); } } hashCodes[hashCodeIdx++] = Arrays.hashCode(innerHashCodes); } else if (value instanceof SparseArray) { SparseArray array = (SparseArray) value; int[] innerHashCodes = new int[array.size() * 2]; for (int j = 0; j < array.size(); j++) { innerHashCodes[j * 2] = array.keyAt(j); Object item = array.valueAt(j); if (item instanceof Bundle) { innerHashCodes[j * 2 + 1] = deepHashCode((Bundle) item); } else if (item != null) { innerHashCodes[j * 2 + 1] = item.hashCode(); } } hashCodes[hashCodeIdx++] = Arrays.hashCode(innerHashCodes); } else { hashCodes[hashCodeIdx++] = value.hashCode(); } } return Arrays.hashCode(hashCodes); } /** * Deeply clones a Bundle. * *

Values which are Bundles, Lists or Arrays are deeply copied themselves. */ @NonNull public static Bundle deepCopy(@NonNull Bundle bundle) { // Write bundle to bytes Parcel parcel = Parcel.obtain(); try { parcel.writeBundle(bundle); byte[] serializedMessage = parcel.marshall(); // Read bundle from bytes parcel.unmarshall(serializedMessage, 0, serializedMessage.length); parcel.setDataPosition(0); return parcel.readBundle(); } finally { parcel.recycle(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy