1 /* 2 * Copyright 2016, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.managedprovisioning.common; 17 18 import android.os.Parcel; 19 import android.os.Parcelable; 20 import android.os.PersistableBundle; 21 import androidx.annotation.NonNull; 22 import android.text.TextUtils; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Collections; 26 import java.util.List; 27 import java.util.Objects; 28 import java.util.Set; 29 30 public abstract class PersistableBundlable implements Parcelable { toPersistableBundle()31 public abstract @NonNull PersistableBundle toPersistableBundle(); 32 getPersistableBundleFromParcel(Parcel parcel)33 public static PersistableBundle getPersistableBundleFromParcel(Parcel parcel) { 34 return parcel.readParcelable(PersistableBundle.class.getClassLoader()); 35 } 36 37 @Override equals(Object object)38 public boolean equals(Object object) { 39 return isPersistableBundlableEquals(this, object); 40 } 41 42 @Override hashCode()43 public int hashCode() { 44 // Concatenated sorted keys should be good enough as a hash 45 List<String> keys = new ArrayList(toPersistableBundle().keySet()); 46 Collections.sort(keys); 47 return TextUtils.join(",", keys).hashCode(); 48 } 49 50 @Override describeContents()51 public int describeContents() { 52 return 0; 53 } 54 55 @Override writeToParcel(Parcel dest, int flags)56 public void writeToParcel(Parcel dest, int flags) { 57 dest.writeParcelable(toPersistableBundle(), flags); 58 } 59 isPersistableBundlableEquals(PersistableBundlable pb1, Object obj)60 private static boolean isPersistableBundlableEquals(PersistableBundlable pb1, Object obj) { 61 if (pb1 == obj) { 62 return true; 63 } 64 if (obj == null || pb1.getClass() != obj.getClass()) { 65 return false; 66 } 67 68 // obj has to be PersistableBundlable as it has the same class 69 PersistableBundlable pb2 = (PersistableBundlable) obj; 70 return isPersistableBundleEquals(pb1.toPersistableBundle(), pb2.toPersistableBundle()); 71 } 72 73 /** 74 * Compares two {@link PersistableBundle} objects are equals. 75 */ isPersistableBundleEquals(PersistableBundle obj1, PersistableBundle obj2)76 private static boolean isPersistableBundleEquals(PersistableBundle obj1, PersistableBundle obj2) { 77 if (obj1 == obj2) { 78 return true; 79 } 80 if (obj1 == null || obj2 == null || obj1.size() != obj2.size()) { 81 return false; 82 } 83 Set<String> keys = obj1.keySet(); 84 for (String key : keys) { 85 Object val1 = obj1.get(key); 86 Object val2 = obj2.get(key); 87 if (!isPersistableBundleSupportedValueEquals(val1, val2)) { 88 return false; 89 } 90 } 91 return true; 92 } 93 94 /** 95 * Compares two values which type is supported by {@link PersistableBundle}. 96 * 97 * <p>If the type isn't supported. The equality is done by {@link Object#equals(Object)}. 98 */ isPersistableBundleSupportedValueEquals(Object val1, Object val2)99 private static boolean isPersistableBundleSupportedValueEquals(Object val1, Object val2) { 100 if (val1 == val2) { 101 return true; 102 } else if (val1 == null || val2 == null || !val1.getClass().equals(val2.getClass())) { 103 return false; 104 } else if (val1 instanceof PersistableBundle) { 105 return isPersistableBundleEquals((PersistableBundle) val1, (PersistableBundle) val2); 106 } else if (val1 instanceof int[]) { 107 return Arrays.equals((int[]) val1, (int[]) val2); 108 } else if (val1 instanceof long[]) { 109 return Arrays.equals((long[]) val1, (long[]) val2); 110 } else if (val1 instanceof double[]) { 111 return Arrays.equals((double[]) val1, (double[]) val2); 112 } else if (val1 instanceof boolean[]) { 113 return Arrays.equals((boolean[]) val1, (boolean[]) val2); 114 } else if (val1 instanceof String[]) { 115 return Arrays.equals((String[]) val1, (String[]) val2); 116 } else { 117 return Objects.equals(val1, val2); 118 } 119 } 120 121 } 122