• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 
17 package android.uwb.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.os.ParcelUuid;
23 import android.os.PersistableBundle;
24 
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.Objects;
38 import java.util.TreeSet;
39 import java.util.concurrent.locks.ReadWriteLock;
40 import java.util.concurrent.locks.ReentrantReadWriteLock;
41 
42 /** @hide */
43 public class PersistableBundleUtils {
44 //    private static final String LIST_KEY_FORMAT = "LIST_ITEM_%d";
45 //    private static final String COLLECTION_SIZE_KEY = "COLLECTION_LENGTH";
46 //    private static final String MAP_KEY_FORMAT = "MAP_KEY_%d";
47 //    private static final String MAP_VALUE_FORMAT = "MAP_VALUE_%d";
48 //
49 //    private static final String PARCEL_UUID_KEY = "PARCEL_UUID";
50 //    private static final String BYTE_ARRAY_KEY = "BYTE_ARRAY_KEY";
51 //    private static final String INTEGER_KEY = "INTEGER_KEY";
52 //    private static final String STRING_KEY = "STRING_KEY";
53 //
54 //    private final static char[] HEX_DIGITS =
55 //            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
56 //    private final static char[] HEX_LOWER_CASE_DIGITS =
57 //            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
58 
59 
60 //    /**
61 //     * Functional interface to convert an object of the specified type to a PersistableBundle.
62 //     *
63 //     * @param <T> the type of the source object
64 //     */
65 //    public interface Serializer<T> {
66 //        /**
67 //         * Converts this object to a PersistableBundle.
68 //         *
69 //         * @return the PersistableBundle representation of this object
70 //         */
71 //        PersistableBundle toPersistableBundle(T obj);
72 //    }
73 //
74 //    /**
75 //     * Functional interface used to create an object of the specified type from a PersistableBundle.
76 //     *
77 //     * @param <T> the type of the resultant object
78 //     */
79 //    public interface Deserializer<T> {
80 //        /**
81 //         * Creates an instance of specified type from a PersistableBundle representation.
82 //         *
83 //         * @param in the PersistableBundle representation
84 //         * @return an instance of the specified type
85 //         */
86 //        T fromPersistableBundle(PersistableBundle in);
87 //    }
88 //
89 //    /** Serializer to convert an integer to a PersistableBundle. */
90 //    public static final Serializer<Integer> INTEGER_SERIALIZER =
91 //            (i) -> {
92 //                final PersistableBundle result = new PersistableBundle();
93 //                result.putInt(INTEGER_KEY, i);
94 //                return result;
95 //            };
96 //
97 //    /** Deserializer to convert a PersistableBundle to an integer. */
98 //    public static final Deserializer<Integer> INTEGER_DESERIALIZER =
99 //            (bundle) -> {
100 //                Objects.requireNonNull(bundle, "PersistableBundle is null");
101 //                return bundle.getInt(INTEGER_KEY);
102 //            };
103 //
104 //    /** Serializer to convert s String to a PersistableBundle. */
105 //    public static final Serializer<String> STRING_SERIALIZER =
106 //            (i) -> {
107 //                final PersistableBundle result = new PersistableBundle();
108 //                result.putString(STRING_KEY, i);
109 //                return result;
110 //            };
111 //
112 //    /** Deserializer to convert a PersistableBundle to a String. */
113 //    public static final Deserializer<String> STRING_DESERIALIZER =
114 //            (bundle) -> {
115 //                Objects.requireNonNull(bundle, "PersistableBundle is null");
116 //                return bundle.getString(STRING_KEY);
117 //            };
118 //
119 //    /**
120 //     * Converts a ParcelUuid to a PersistableBundle.
121 //     *
122 //     * <p>To avoid key collisions, NO additional key/value pairs should be added to the returned
123 //     * PersistableBundle object.
124 //     *
125 //     * @param uuid a ParcelUuid instance to persist
126 //     * @return the PersistableBundle instance
127 //     */
128 //    public static PersistableBundle fromParcelUuid(ParcelUuid uuid) {
129 //        final PersistableBundle result = new PersistableBundle();
130 //
131 //        result.putString(PARCEL_UUID_KEY, uuid.toString());
132 //
133 //        return result;
134 //    }
135 //
136 //    /**
137 //     * Converts from a PersistableBundle to a ParcelUuid.
138 //     *
139 //     * @param bundle the PersistableBundle containing the ParcelUuid
140 //     * @return the ParcelUuid instance
141 //     */
142 //    public static ParcelUuid toParcelUuid(PersistableBundle bundle) {
143 //        return ParcelUuid.fromString(bundle.getString(PARCEL_UUID_KEY));
144 //    }
145 //
146 //    /**
147 //     * Converts from a list of Persistable objects to a single PersistableBundle.
148 //     *
149 //     * <p>To avoid key collisions, NO additional key/value pairs should be added to the returned
150 //     * PersistableBundle object.
151 //     *
152 //     * @param <T>        the type of the objects to convert to the PersistableBundle
153 //     * @param in         the list of objects to be serialized into a PersistableBundle
154 //     * @param serializer an implementation of the {@link Serializer} functional interface that
155 //     *                   converts an object of type T to a PersistableBundle
156 //     */
157 //    @NonNull
158 //    public static <T> PersistableBundle fromList(
159 //            @NonNull List<T> in, @NonNull Serializer<T> serializer) {
160 //        final PersistableBundle result = new PersistableBundle();
161 //
162 //        result.putInt(COLLECTION_SIZE_KEY, in.size());
163 //        for (int i = 0; i < in.size(); i++) {
164 //            final String key = String.format(LIST_KEY_FORMAT, i);
165 //            result.putPersistableBundle(key, serializer.toPersistableBundle(in.get(i)));
166 //        }
167 //        return result;
168 //    }
169 //
170 //    /**
171 //     * Converts from a PersistableBundle to a list of objects.
172 //     *
173 //     * @param <T>          the type of the objects to convert from a PersistableBundle
174 //     * @param in           the PersistableBundle containing the persisted list
175 //     * @param deserializer an implementation of the {@link Deserializer} functional interface that
176 //     *                     builds the relevant type of objects.
177 //     */
178 //    @NonNull
179 //    public static <T> List<T> toList(
180 //            @NonNull PersistableBundle in, @NonNull Deserializer<T> deserializer) {
181 //        final int listLength = in.getInt(COLLECTION_SIZE_KEY);
182 //        final ArrayList<T> result = new ArrayList<>(listLength);
183 //
184 //        for (int i = 0; i < listLength; i++) {
185 //            final String key = String.format(LIST_KEY_FORMAT, i);
186 //            final PersistableBundle item = in.getPersistableBundle(key);
187 //
188 //            result.add(deserializer.fromPersistableBundle(item));
189 //        }
190 //        return result;
191 //    }
192 //
193 //    // TODO: b/170513329 Delete #fromByteArray and #toByteArray once BaseBundle#putByteArray and
194 //    // BaseBundle#getByteArray are exposed.
195 //
196 //    /**
197 //     * Converts a byte array to a PersistableBundle.
198 //     *
199 //     * <p>To avoid key collisions, NO additional key/value pairs should be added to the returned
200 //     * PersistableBundle object.
201 //     *
202 //     * @param array a byte array instance to persist
203 //     * @return the PersistableBundle instance
204 //     */
205 //    public static PersistableBundle fromByteArray(byte[] array) {
206 //        final PersistableBundle result = new PersistableBundle();
207 //
208 //        result.putString(BYTE_ARRAY_KEY, toHexString(array));
209 //
210 //        return result;
211 //    }
212 //
213 //    // Copied from com.android.internal.util.HexDump
214 //    @UnsupportedAppUsage
215 //    public static String toHexString(byte[] array, int offset, int length) {
216 //        return toHexString(array, offset, length, true);
217 //    }
218 //
219 //    public static String toHexString(byte[] array, int offset, int length, boolean upperCase) {
220 //        char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS;
221 //        char[] buf = new char[length * 2];
222 //
223 //        int bufIndex = 0;
224 //        for (int i = offset; i < offset + length; i++) {
225 //            byte b = array[i];
226 //            buf[bufIndex++] = digits[(b >>> 4) & 0x0F];
227 //            buf[bufIndex++] = digits[b & 0x0F];
228 //        }
229 //
230 //        return new String(buf);
231 //    }
232 //
233 //    @UnsupportedAppUsage
234 //    public static String toHexString(byte[] array) {
235 //        return toHexString(array, 0, array.length, true);
236 //    }
237 //
238 //    @UnsupportedAppUsage
239 //    public static String toHexString(int i) {
240 //        return toHexString(toByteArray(i));
241 //    }
242 //
243 //    public static byte[] toByteArray(int i) {
244 //        byte[] array = new byte[4];
245 //
246 //        array[3] = (byte) (i & 0xFF);
247 //        array[2] = (byte) ((i >> 8) & 0xFF);
248 //        array[1] = (byte) ((i >> 16) & 0xFF);
249 //        array[0] = (byte) ((i >> 24) & 0xFF);
250 //
251 //        return array;
252 //    }
253 //
254 //    @UnsupportedAppUsage
255 //    public static byte[] hexStringToByteArray(String hexString) {
256 //        int length = hexString.length();
257 //        byte[] buffer = new byte[length / 2];
258 //
259 //        for (int i = 0; i < length; i += 2) {
260 //            buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(
261 //                    hexString.charAt(i + 1)));
262 //        }
263 //
264 //        return buffer;
265 //    }
266 //
267 //    private static int toByte(char c) {
268 //        if (c >= '0' && c <= '9') return (c - '0');
269 //        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
270 //        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
271 //
272 //        throw new RuntimeException("Invalid hex char '" + c + "'");
273 //    }
274 //
275 //    /**
276 //     * Converts from a PersistableBundle to a byte array.
277 //     *
278 //     * @param bundle the PersistableBundle containing the byte array
279 //     * @return the byte array instance
280 //     */
281 //    public static byte[] toByteArray(PersistableBundle bundle) {
282 //        Objects.requireNonNull(bundle, "PersistableBundle is null");
283 //
284 //        String hex = bundle.getString(BYTE_ARRAY_KEY);
285 //        if (hex == null || hex.length() % 2 != 0) {
286 //            throw new IllegalArgumentException("PersistableBundle contains invalid byte array");
287 //        }
288 //
289 //        return hexStringToByteArray(hex);
290 //    }
291 //
292 //    /**
293 //     * Converts from a Map of Persistable objects to a single PersistableBundle.
294 //     *
295 //     * <p>To avoid key collisions, NO additional key/value pairs should be added to the returned
296 //     * PersistableBundle object.
297 //     *
298 //     * @param <K>             the type of the map-key to convert to the PersistableBundle
299 //     * @param <V>             the type of the map-value to convert to the PersistableBundle
300 //     * @param in              the Map of objects implementing the {@link Persistable} interface
301 //     * @param keySerializer   an implementation of the {@link Serializer} functional interface that
302 //     *                        converts a map-key of type T to a PersistableBundle
303 //     * @param valueSerializer an implementation of the {@link Serializer} functional interface that
304 //     *                        converts a map-value of type E to a PersistableBundle
305 //     */
306 //    @NonNull
307 //    public static <K, V> PersistableBundle fromMap(
308 //            @NonNull Map<K, V> in,
309 //            @NonNull Serializer<K> keySerializer,
310 //            @NonNull Serializer<V> valueSerializer) {
311 //        final PersistableBundle result = new PersistableBundle();
312 //
313 //        result.putInt(COLLECTION_SIZE_KEY, in.size());
314 //        int i = 0;
315 //        for (Entry<K, V> entry : in.entrySet()) {
316 //            final String keyKey = String.format(MAP_KEY_FORMAT, i);
317 //            final String valueKey = String.format(MAP_VALUE_FORMAT, i);
318 //            result.putPersistableBundle(keyKey, keySerializer.toPersistableBundle(entry.getKey()));
319 //            result.putPersistableBundle(
320 //                    valueKey, valueSerializer.toPersistableBundle(entry.getValue()));
321 //
322 //            i++;
323 //        }
324 //
325 //        return result;
326 //    }
327 //
328 //    /**
329 //     * Converts from a PersistableBundle to a Map of objects.
330 //     *
331 //     * <p>In an attempt to preserve ordering, the returned map will be a LinkedHashMap. However, the
332 //     * guarantees on the ordering can only ever be as strong as the map that was serialized in
333 //     * {@link fromMap()}. If the initial map that was serialized had no ordering guarantees, the
334 //     * deserialized map similarly may be of a non-deterministic order.
335 //     *
336 //     * @param <K>               the type of the map-key to convert from a PersistableBundle
337 //     * @param <V>               the type of the map-value to convert from a PersistableBundle
338 //     * @param in                the PersistableBundle containing the persisted Map
339 //     * @param keyDeserializer   an implementation of the {@link Deserializer} functional interface
340 //     *                          that builds the relevant type of map-key.
341 //     * @param valueDeserializer an implementation of the {@link Deserializer} functional interface
342 //     *                          that builds the relevant type of map-value.
343 //     * @return An instance of the parsed map as a LinkedHashMap (in an attempt to preserve
344 //     * ordering).
345 //     */
346 //    @NonNull
347 //    public static <K, V> LinkedHashMap<K, V> toMap(
348 //            @NonNull PersistableBundle in,
349 //            @NonNull Deserializer<K> keyDeserializer,
350 //            @NonNull Deserializer<V> valueDeserializer) {
351 //        final int mapSize = in.getInt(COLLECTION_SIZE_KEY);
352 //        final LinkedHashMap<K, V> result = new LinkedHashMap<>(mapSize);
353 //
354 //        for (int i = 0; i < mapSize; i++) {
355 //            final String keyKey = String.format(MAP_KEY_FORMAT, i);
356 //            final String valueKey = String.format(MAP_VALUE_FORMAT, i);
357 //            final PersistableBundle keyBundle = in.getPersistableBundle(keyKey);
358 //            final PersistableBundle valueBundle = in.getPersistableBundle(valueKey);
359 //
360 //            final K key = keyDeserializer.fromPersistableBundle(keyBundle);
361 //            final V value = valueDeserializer.fromPersistableBundle(valueBundle);
362 //            result.put(key, value);
363 //        }
364 //        return result;
365 //    }
366 //
367 //    /**
368 //     * Converts a PersistableBundle into a disk-stable byte array format
369 //     *
370 //     * @param bundle the PersistableBundle to be converted to a disk-stable format
371 //     * @return the byte array representation of the PersistableBundle
372 //     */
373 //    @Nullable
374 //    public static byte[] toDiskStableBytes(@NonNull PersistableBundle bundle) throws IOException {
375 //        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
376 //        bundle.writeToStream(outputStream);
377 //        return outputStream.toByteArray();
378 //    }
379 //
380 //    /**
381 //     * Converts from a disk-stable byte array format to a PersistableBundle
382 //     *
383 //     * @param bytes the disk-stable byte array
384 //     * @return the PersistableBundle parsed from this byte array.
385 //     */
386 //    public static PersistableBundle fromDiskStableBytes(@NonNull byte[] bytes) throws IOException {
387 //        final ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
388 //        return PersistableBundle.readFromStream(inputStream);
389 //    }
390 //
391 //    /**
392 //     * Ensures safe reading and writing of {@link PersistableBundle}s to and from disk.
393 //     *
394 //     * <p>This class will enforce exclusion between reads and writes using the standard semantics of
395 //     * a ReadWriteLock. Specifically, concurrent readers ARE allowed, but reads/writes from/to the
396 //     * file are mutually exclusive. In other words, for an unbounded number n, the acceptable states
397 //     * are n readers, OR 1 writer (but not both).
398 //     */
399 //    public static class LockingReadWriteHelper {
400 //        private final ReadWriteLock mDiskLock = new ReentrantReadWriteLock();
401 //        private final String mPath;
402 //
403 //        public LockingReadWriteHelper(@NonNull String path) {
404 //            mPath = Objects.requireNonNull(path, "fileName was null");
405 //        }
406 //
407 //        /**
408 //         * Reads the {@link PersistableBundle} from the disk.
409 //         *
410 //         * @return the PersistableBundle, if the file existed, or null otherwise
411 //         */
412 //        @Nullable
413 //        public PersistableBundle readFromDisk() throws IOException {
414 //            try {
415 //                mDiskLock.readLock().lock();
416 //                final File file = new File(mPath);
417 //                if (!file.exists()) {
418 //                    return null;
419 //                }
420 //
421 //                try (FileInputStream fis = new FileInputStream(file)) {
422 //                    return PersistableBundle.readFromStream(fis);
423 //                }
424 //            } finally {
425 //                mDiskLock.readLock().unlock();
426 //            }
427 //        }
428 //
429 //        /**
430 //         * Writes a {@link PersistableBundle} to disk.
431 //         *
432 //         * @param bundle the {@link PersistableBundle} to write to disk
433 //         */
434 //        public void writeToDisk(@NonNull PersistableBundle bundle) throws IOException {
435 //            Objects.requireNonNull(bundle, "bundle was null");
436 //
437 //            try {
438 //                mDiskLock.writeLock().lock();
439 //                final File file = new File(mPath);
440 //                if (!file.exists()) {
441 //                    file.getParentFile().mkdirs();
442 //                }
443 //
444 //                try (FileOutputStream fos = new FileOutputStream(file)) {
445 //                    bundle.writeToStream(fos);
446 //                }
447 //            } finally {
448 //                mDiskLock.writeLock().unlock();
449 //            }
450 //        }
451 //    }
452 //
453 //    /**
454 //     * Returns a copy of the persistable bundle with only the specified keys
455 //     *
456 //     * <p>This allows for holding minimized copies for memory-saving purposes.
457 //     */
458 //    @NonNull
459 //    public static PersistableBundle minimizeBundle(
460 //            @NonNull PersistableBundle bundle, String... keys) {
461 //        final PersistableBundle minimized = new PersistableBundle();
462 //
463 //        if (bundle == null) {
464 //            return minimized;
465 //        }
466 //
467 //        for (String key : keys) {
468 //            if (bundle.containsKey(key)) {
469 //                final Object value = bundle.get(key);
470 //                if (value == null) {
471 //                    continue;
472 //                }
473 //
474 //                if (value instanceof Boolean) {
475 //                    minimized.putBoolean(key, (Boolean) value);
476 //                } else if (value instanceof boolean[]) {
477 //                    minimized.putBooleanArray(key, (boolean[]) value);
478 //                } else if (value instanceof Double) {
479 //                    minimized.putDouble(key, (Double) value);
480 //                } else if (value instanceof double[]) {
481 //                    minimized.putDoubleArray(key, (double[]) value);
482 //                } else if (value instanceof Integer) {
483 //                    minimized.putInt(key, (Integer) value);
484 //                } else if (value instanceof int[]) {
485 //                    minimized.putIntArray(key, (int[]) value);
486 //                } else if (value instanceof Long) {
487 //                    minimized.putLong(key, (Long) value);
488 //                } else if (value instanceof long[]) {
489 //                    minimized.putLongArray(key, (long[]) value);
490 //                } else if (value instanceof String) {
491 //                    minimized.putString(key, (String) value);
492 //                } else if (value instanceof String[]) {
493 //                    minimized.putStringArray(key, (String[]) value);
494 //                } else if (value instanceof PersistableBundle) {
495 //                    minimized.putPersistableBundle(key, (PersistableBundle) value);
496 //                } else {
497 //                    continue;
498 //                }
499 //            }
500 //        }
501 //
502 //        return minimized;
503 //    }
504 
505     /** Builds a stable hashcode */
getHashCode(@ullable PersistableBundle bundle)506     public static int getHashCode(@Nullable PersistableBundle bundle) {
507         if (bundle == null) {
508             return -1;
509         }
510 
511         int iterativeHashcode = 0;
512         TreeSet<String> treeSet = new TreeSet<>(bundle.keySet());
513         for (String key : treeSet) {
514             Object val = bundle.get(key);
515             if (val instanceof PersistableBundle) {
516                 iterativeHashcode =
517                         Objects.hash(iterativeHashcode, key, getHashCode((PersistableBundle) val));
518             } else {
519                 iterativeHashcode = Objects.hash(iterativeHashcode, key, val);
520             }
521         }
522 
523         return iterativeHashcode;
524     }
525 
526     /** Checks for persistable bundle equality */
isEqual( @ullable PersistableBundle left, @Nullable PersistableBundle right)527     public static boolean isEqual(
528             @Nullable PersistableBundle left, @Nullable PersistableBundle right) {
529         // Check for pointer equality & null equality
530         if (Objects.equals(left, right)) {
531             return true;
532         }
533 
534         // If only one of the two is null, but not the other, not equal by definition.
535         if (Objects.isNull(left) != Objects.isNull(right)) {
536             return false;
537         }
538 
539         if (!left.keySet().equals(right.keySet())) {
540             return false;
541         }
542 
543         for (String key : left.keySet()) {
544             Object leftVal = left.get(key);
545             Object rightVal = right.get(key);
546 
547             // Check for equality
548             if (Objects.equals(leftVal, rightVal)) {
549                 continue;
550             } else if (Objects.isNull(leftVal) != Objects.isNull(rightVal)) {
551                 // If only one of the two is null, but not the other, not equal by definition.
552                 return false;
553             } else if (!Objects.equals(leftVal.getClass(), rightVal.getClass())) {
554                 // If classes are different, not equal by definition.
555                 return false;
556             }
557             if (leftVal instanceof PersistableBundle) {
558                 if (!isEqual((PersistableBundle) leftVal, (PersistableBundle) rightVal)) {
559                     return false;
560                 }
561             } else if (leftVal.getClass().isArray()) {
562                 if (leftVal instanceof boolean[]) {
563                     if (!Arrays.equals((boolean[]) leftVal, (boolean[]) rightVal)) {
564                         return false;
565                     }
566                 } else if (leftVal instanceof double[]) {
567                     if (!Arrays.equals((double[]) leftVal, (double[]) rightVal)) {
568                         return false;
569                     }
570                 } else if (leftVal instanceof int[]) {
571                     if (!Arrays.equals((int[]) leftVal, (int[]) rightVal)) {
572                         return false;
573                     }
574                 } else if (leftVal instanceof long[]) {
575                     if (!Arrays.equals((long[]) leftVal, (long[]) rightVal)) {
576                         return false;
577                     }
578                 } else if (!Arrays.equals((Object[]) leftVal, (Object[]) rightVal)) {
579                     return false;
580                 }
581             } else {
582                 if (!Objects.equals(leftVal, rightVal)) {
583                     return false;
584                 }
585             }
586         }
587 
588         return true;
589     }
590 
591 //    /**
592 //     * Wrapper class around PersistableBundles to allow equality comparisons
593 //     *
594 //     * <p>This class exposes the minimal getters to retrieve values.
595 //     */
596 //    public static class PersistableBundleWrapper {
597 //        @NonNull
598 //        private final PersistableBundle mBundle;
599 //
600 //        public PersistableBundleWrapper(@NonNull PersistableBundle bundle) {
601 //            mBundle = Objects.requireNonNull(bundle, "Bundle was null");
602 //        }
603 //
604 //        /**
605 //         * Retrieves the integer associated with the provided key.
606 //         *
607 //         * @param key          the string key to query
608 //         * @param defaultValue the value to return if key does not exist
609 //         * @return the int value, or the default
610 //         */
611 //        public int getInt(String key, int defaultValue) {
612 //            return mBundle.getInt(key, defaultValue);
613 //        }
614 //
615 //        @Override
616 //        public int hashCode() {
617 //            return getHashCode(mBundle);
618 //        }
619 //
620 //        @Override
621 //        public boolean equals(Object obj) {
622 //            if (!(obj instanceof PersistableBundleWrapper)) {
623 //                return false;
624 //            }
625 //
626 //            final PersistableBundleWrapper other = (PersistableBundleWrapper) obj;
627 //
628 //            return isEqual(mBundle, other.mBundle);
629 //        }
630 //    }
631 }
632