1 /*
2  * Copyright (C) 2008 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.os.cts;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertNotSame;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertSame;
28 import static org.junit.Assert.assertThrows;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.fail;
31 
32 import static java.util.Collections.singletonList;
33 
34 import android.content.Intent;
35 import android.os.Bundle;
36 import android.os.Parcel;
37 import android.os.ParcelFileDescriptor;
38 import android.os.Parcelable;
39 import android.platform.test.annotations.AppModeSdkSandbox;
40 import android.platform.test.annotations.IgnoreUnderRavenwood;
41 import android.platform.test.ravenwood.RavenwoodRule;
42 import android.text.Spannable;
43 import android.text.SpannableString;
44 import android.text.style.ForegroundColorSpan;
45 import android.util.SparseArray;
46 
47 import org.junit.After;
48 import org.junit.Before;
49 import org.junit.Rule;
50 import org.junit.Test;
51 
52 import java.io.File;
53 import java.io.FileDescriptor;
54 import java.io.FileNotFoundException;
55 import java.io.IOException;
56 import java.io.ObjectInputStream;
57 import java.io.Serializable;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Objects;
61 import java.util.Set;
62 import java.util.concurrent.Callable;
63 
64 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
65 public class BundleTest {
66     @Rule public RavenwoodRule mRavenwood = new RavenwoodRule();
67 
68     private static final boolean BOOLEANKEYVALUE = false;
69     private static final int INTKEYVALUE = 20;
70     private static final String INTKEY = "intkey";
71     private static final String BOOLEANKEY = "booleankey";
72 
73     /** Keys should be in hash code order */
74     private static final String KEY1 = "key1";
75     private static final String KEY2 = "key2";
76 
77     private Bundle mBundle;
78     private Spannable mSpannable;
79 
80     @Before
setUp()81     public void setUp() throws Exception {
82         mBundle = new Bundle();
83         mBundle.setClassLoader(getClass().getClassLoader());
84     }
85 
initSpannable()86     private void initSpannable() {
87         mSpannable = new SpannableString("foo bar");
88         mSpannable.setSpan(new ForegroundColorSpan(0x123456), 0, 3, 0);
89     }
90 
91     @After
tearDown()92     public void tearDown() throws Exception {
93         CustomParcelable.sDeserialized = false;
94         CustomSerializable.sDeserialized = false;
95     }
96 
97     @Test
testBundle()98     public void testBundle() {
99         final Bundle b1 = new Bundle();
100         assertTrue(b1.isEmpty());
101         b1.putBoolean(KEY1, true);
102         assertFalse(b1.isEmpty());
103 
104         final Bundle b2 = new Bundle(b1);
105         assertTrue(b2.getBoolean(KEY1));
106 
107         new Bundle(1024);
108         new Bundle(getClass().getClassLoader());
109     }
110 
111     @Test
testEmptyStream()112     public void testEmptyStream() {
113         Parcel p = Parcel.obtain();
114         p.unmarshall(new byte[] {}, 0, 0);
115         Bundle b = p.readBundle();
116         assertTrue(b.isEmpty());
117         mBundle.putBoolean("android", true);
118         p.unmarshall(new byte[] {}, 0, 0);
119         mBundle.readFromParcel(p);
120         assertTrue(mBundle.isEmpty());
121     }
122 
123     // first put sth into tested Bundle, it shouldn't be empty, then clear it and it should be empty
124     @Test
testClear()125     public void testClear() {
126         mBundle.putBoolean("android", true);
127         mBundle.putBoolean(KEY1, true);
128         assertFalse(mBundle.isEmpty());
129         mBundle.clear();
130         assertTrue(mBundle.isEmpty());
131     }
132 
133     // first clone the tested Bundle, then compare the original Bundle with the
134     // cloned Bundle, they should equal
135     @Test
testClone()136     public void testClone() {
137         mBundle.putBoolean(BOOLEANKEY, BOOLEANKEYVALUE);
138         mBundle.putInt(INTKEY, INTKEYVALUE);
139         Bundle cloneBundle = (Bundle) mBundle.clone();
140         assertEquals(mBundle.size(), cloneBundle.size());
141         assertEquals(mBundle.getBoolean(BOOLEANKEY), cloneBundle.getBoolean(BOOLEANKEY));
142         assertEquals(mBundle.getInt(INTKEY), cloneBundle.getInt(INTKEY));
143     }
144 
145     // containsKey would return false if nothing has been put into the Bundle,
146     // else containsKey would return true if any putXXX has been called before
147     @Test
testContainsKey()148     public void testContainsKey() {
149         assertFalse(mBundle.containsKey(KEY1));
150         mBundle.putBoolean(KEY1, true);
151         assertTrue(mBundle.containsKey(KEY1));
152         roundtrip();
153         assertTrue(mBundle.containsKey(KEY1));
154     }
155 
156     // get would return null if nothing has been put into the Bundle,else get
157     // would return the value set by putXXX
158     @Test
testGet()159     public void testGet() {
160         assertNull(mBundle.get(KEY1));
161         mBundle.putBoolean(KEY1, true);
162         assertNotNull(mBundle.get(KEY1));
163         roundtrip();
164         assertNotNull(mBundle.get(KEY1));
165     }
166 
167     @Test
testGetBoolean1()168     public void testGetBoolean1() {
169         assertFalse(mBundle.getBoolean(KEY1));
170         mBundle.putBoolean(KEY1, true);
171         assertTrue(mBundle.getBoolean(KEY1));
172         roundtrip();
173         assertTrue(mBundle.getBoolean(KEY1));
174     }
175 
176     @Test
testGetBoolean2()177     public void testGetBoolean2() {
178         assertTrue(mBundle.getBoolean(KEY1, true));
179         mBundle.putBoolean(KEY1, false);
180         assertFalse(mBundle.getBoolean(KEY1, true));
181         roundtrip();
182         assertFalse(mBundle.getBoolean(KEY1, true));
183     }
184 
185     @Test
testGetBooleanArray()186     public void testGetBooleanArray() {
187         assertNull(mBundle.getBooleanArray(KEY1));
188         mBundle.putBooleanArray(KEY1, new boolean[] {
189                 true, false, true
190         });
191         boolean[] booleanArray = mBundle.getBooleanArray(KEY1);
192         assertNotNull(booleanArray);
193         assertEquals(3, booleanArray.length);
194         assertEquals(true, booleanArray[0]);
195         assertEquals(false, booleanArray[1]);
196         assertEquals(true, booleanArray[2]);
197         roundtrip();
198         booleanArray = mBundle.getBooleanArray(KEY1);
199         assertNotNull(booleanArray);
200         assertEquals(3, booleanArray.length);
201         assertEquals(true, booleanArray[0]);
202         assertEquals(false, booleanArray[1]);
203         assertEquals(true, booleanArray[2]);
204     }
205 
206     @Test
testGetBundle()207     public void testGetBundle() {
208         assertNull(mBundle.getBundle(KEY1));
209         final Bundle bundle = new Bundle();
210         mBundle.putBundle(KEY1, bundle);
211         assertTrue(bundle.equals(mBundle.getBundle(KEY1)));
212         roundtrip();
213         assertBundleEquals(bundle, mBundle.getBundle(KEY1));
214     }
215 
216     @Test
testGetByte1()217     public void testGetByte1() {
218         final byte b = 7;
219 
220         assertEquals(0, mBundle.getByte(KEY1));
221         mBundle.putByte(KEY1, b);
222         assertEquals(b, mBundle.getByte(KEY1));
223         roundtrip();
224         assertEquals(b, mBundle.getByte(KEY1));
225     }
226 
227     @Test
testGetByte2()228     public void testGetByte2() {
229         final byte b1 = 6;
230         final byte b2 = 7;
231 
232         assertEquals((Byte)b1, mBundle.getByte(KEY1, b1));
233         mBundle.putByte(KEY1, b2);
234         assertEquals((Byte)b2, mBundle.getByte(KEY1, b1));
235         roundtrip();
236         assertEquals((Byte)b2, mBundle.getByte(KEY1, b1));
237     }
238 
239     @Test
testGetByteArray()240     public void testGetByteArray() {
241         assertNull(mBundle.getByteArray(KEY1));
242         mBundle.putByteArray(KEY1, new byte[] {
243                 1, 2, 3
244         });
245         byte[] byteArray = mBundle.getByteArray(KEY1);
246         assertNotNull(byteArray);
247         assertEquals(3, byteArray.length);
248         assertEquals(1, byteArray[0]);
249         assertEquals(2, byteArray[1]);
250         assertEquals(3, byteArray[2]);
251         roundtrip();
252         byteArray = mBundle.getByteArray(KEY1);
253         assertNotNull(byteArray);
254         assertEquals(3, byteArray.length);
255         assertEquals(1, byteArray[0]);
256         assertEquals(2, byteArray[1]);
257         assertEquals(3, byteArray[2]);
258     }
259 
260     @Test
testGetChar1()261     public void testGetChar1() {
262         final char c = 'l';
263 
264         assertEquals((char)0, mBundle.getChar(KEY1));
265         mBundle.putChar(KEY1, c);
266         assertEquals(c, mBundle.getChar(KEY1));
267         roundtrip();
268         assertEquals(c, mBundle.getChar(KEY1));
269     }
270 
271     @Test
testGetChar2()272     public void testGetChar2() {
273         final char c1 = 'l';
274         final char c2 = 'i';
275 
276         assertEquals(c1, mBundle.getChar(KEY1, c1));
277         mBundle.putChar(KEY1, c2);
278         assertEquals(c2, mBundle.getChar(KEY1, c1));
279         roundtrip();
280         assertEquals(c2, mBundle.getChar(KEY1, c1));
281     }
282 
283     @Test
testGetCharArray()284     public void testGetCharArray() {
285         assertNull(mBundle.getCharArray(KEY1));
286         mBundle.putCharArray(KEY1, new char[] {
287                 'h', 'i'
288         });
289         char[] charArray = mBundle.getCharArray(KEY1);
290         assertEquals('h', charArray[0]);
291         assertEquals('i', charArray[1]);
292         roundtrip();
293         charArray = mBundle.getCharArray(KEY1);
294         assertEquals('h', charArray[0]);
295         assertEquals('i', charArray[1]);
296     }
297 
298     @Test
299     @IgnoreUnderRavenwood(blockedBy = SpannableString.class)
testGetCharSequence()300     public void testGetCharSequence() {
301         initSpannable();
302         final CharSequence cS = "Bruce Lee";
303 
304         assertNull(mBundle.getCharSequence(KEY1));
305         assertNull(mBundle.getCharSequence(KEY2));
306         mBundle.putCharSequence(KEY1, cS);
307         mBundle.putCharSequence(KEY2, mSpannable);
308         assertEquals(cS, mBundle.getCharSequence(KEY1));
309         assertSpannableEquals(mSpannable, mBundle.getCharSequence(KEY2));
310         roundtrip();
311         assertEquals(cS, mBundle.getCharSequence(KEY1));
312         assertSpannableEquals(mSpannable, mBundle.getCharSequence(KEY2));
313     }
314 
315     @Test
316     @IgnoreUnderRavenwood(blockedBy = SpannableString.class)
testGetCharSequenceArray()317     public void testGetCharSequenceArray() {
318         initSpannable();
319         assertNull(mBundle.getCharSequenceArray(KEY1));
320         mBundle.putCharSequenceArray(KEY1, new CharSequence[] {
321                 "one", "two", "three", mSpannable
322         });
323         CharSequence[] ret = mBundle.getCharSequenceArray(KEY1);
324         assertEquals(4, ret.length);
325         assertEquals("one", ret[0]);
326         assertEquals("two", ret[1]);
327         assertEquals("three", ret[2]);
328         assertSpannableEquals(mSpannable, ret[3]);
329         roundtrip();
330         ret = mBundle.getCharSequenceArray(KEY1);
331         assertEquals(4, ret.length);
332         assertEquals("one", ret[0]);
333         assertEquals("two", ret[1]);
334         assertEquals("three", ret[2]);
335         assertSpannableEquals(mSpannable, ret[3]);
336     }
337 
338     @Test
339     @IgnoreUnderRavenwood(blockedBy = SpannableString.class)
testGetCharSequenceArrayList()340     public void testGetCharSequenceArrayList() {
341         initSpannable();
342         assertNull(mBundle.getCharSequenceArrayList(KEY1));
343         final ArrayList<CharSequence> list = new ArrayList<CharSequence>();
344         list.add("one");
345         list.add("two");
346         list.add("three");
347         list.add(mSpannable);
348         mBundle.putCharSequenceArrayList(KEY1, list);
349         roundtrip();
350         ArrayList<CharSequence> ret = mBundle.getCharSequenceArrayList(KEY1);
351         assertEquals(4, ret.size());
352         assertEquals("one", ret.get(0));
353         assertEquals("two", ret.get(1));
354         assertEquals("three", ret.get(2));
355         assertSpannableEquals(mSpannable, ret.get(3));
356         roundtrip();
357         ret = mBundle.getCharSequenceArrayList(KEY1);
358         assertEquals(4, ret.size());
359         assertEquals("one", ret.get(0));
360         assertEquals("two", ret.get(1));
361         assertEquals("three", ret.get(2));
362         assertSpannableEquals(mSpannable, ret.get(3));
363     }
364 
365     @Test
testGetDouble1()366     public void testGetDouble1() {
367         final double d = 10.07;
368 
369         assertEquals(0.0, mBundle.getDouble(KEY1), 0.0);
370         mBundle.putDouble(KEY1, d);
371         assertEquals(d, mBundle.getDouble(KEY1), 0.0);
372         roundtrip();
373         assertEquals(d, mBundle.getDouble(KEY1), 0.0);
374     }
375 
376     @Test
testGetDouble2()377     public void testGetDouble2() {
378         final double d1 = 10.06;
379         final double d2 = 10.07;
380 
381         assertEquals(d1, mBundle.getDouble(KEY1, d1), 0.0);
382         mBundle.putDouble(KEY1, d2);
383         assertEquals(d2, mBundle.getDouble(KEY1, d1), 0.0);
384         roundtrip();
385         assertEquals(d2, mBundle.getDouble(KEY1, d1), 0.0);
386     }
387 
388     @Test
testGetDoubleArray()389     public void testGetDoubleArray() {
390         assertNull(mBundle.getDoubleArray(KEY1));
391         mBundle.putDoubleArray(KEY1, new double[] {
392                 10.06, 10.07
393         });
394         double[] doubleArray = mBundle.getDoubleArray(KEY1);
395         assertEquals(10.06, doubleArray[0], 0.0);
396         assertEquals(10.07, doubleArray[1], 0.0);
397         roundtrip();
398         doubleArray = mBundle.getDoubleArray(KEY1);
399         assertEquals(10.06, doubleArray[0], 0.0);
400         assertEquals(10.07, doubleArray[1], 0.0);
401     }
402 
403     @Test
testGetFloat1()404     public void testGetFloat1() {
405         final float f = 10.07f;
406 
407         assertEquals(0.0f, mBundle.getFloat(KEY1), 0.0f);
408         mBundle.putFloat(KEY1, f);
409         assertEquals(f, mBundle.getFloat(KEY1), 0.0f);
410         roundtrip();
411         assertEquals(f, mBundle.getFloat(KEY1), 0.0f);
412     }
413 
414     @Test
testGetFloat2()415     public void testGetFloat2() {
416         final float f1 = 10.06f;
417         final float f2 = 10.07f;
418 
419         assertEquals(f1, mBundle.getFloat(KEY1, f1), 0.0f);
420         mBundle.putFloat(KEY1, f2);
421         assertEquals(f2, mBundle.getFloat(KEY1, f1), 0.0f);
422         roundtrip();
423         assertEquals(f2, mBundle.getFloat(KEY1, f1), 0.0f);
424     }
425 
426     @Test
testGetFloatArray()427     public void testGetFloatArray() {
428         assertNull(mBundle.getFloatArray(KEY1));
429         mBundle.putFloatArray(KEY1, new float[] {
430                 10.06f, 10.07f
431         });
432         float[] floatArray = mBundle.getFloatArray(KEY1);
433         assertEquals(10.06f, floatArray[0], 0.0f);
434         assertEquals(10.07f, floatArray[1], 0.0f);
435         roundtrip();
436         floatArray = mBundle.getFloatArray(KEY1);
437         assertEquals(10.06f, floatArray[0], 0.0f);
438         assertEquals(10.07f, floatArray[1], 0.0f);
439     }
440 
441     @Test
testGetInt1()442     public void testGetInt1() {
443         final int i = 1007;
444 
445         assertEquals(0, mBundle.getInt(KEY1));
446         mBundle.putInt(KEY1, i);
447         assertEquals(i, mBundle.getInt(KEY1));
448         roundtrip();
449         assertEquals(i, mBundle.getInt(KEY1));
450     }
451 
452     @Test
testGetInt2()453     public void testGetInt2() {
454         final int i1 = 1006;
455         final int i2 = 1007;
456 
457         assertEquals(i1, mBundle.getInt(KEY1, i1));
458         mBundle.putInt(KEY1, i2);
459         assertEquals(i2, mBundle.getInt(KEY1, i2));
460         roundtrip();
461         assertEquals(i2, mBundle.getInt(KEY1, i2));
462     }
463 
464     @Test
testGetIntArray()465     public void testGetIntArray() {
466         assertNull(mBundle.getIntArray(KEY1));
467         mBundle.putIntArray(KEY1, new int[] {
468                 1006, 1007
469         });
470         int[] intArray = mBundle.getIntArray(KEY1);
471         assertEquals(1006, intArray[0]);
472         assertEquals(1007, intArray[1]);
473         roundtrip();
474         intArray = mBundle.getIntArray(KEY1);
475         assertEquals(1006, intArray[0]);
476         assertEquals(1007, intArray[1]);
477     }
478 
479     // getIntegerArrayList should only return the IntegerArrayList set by putIntegerArrayLis
480     @Test
testGetIntegerArrayList()481     public void testGetIntegerArrayList() {
482         final int i1 = 1006;
483         final int i2 = 1007;
484 
485         assertNull(mBundle.getIntegerArrayList(KEY1));
486         final ArrayList<Integer> arrayList = new ArrayList<Integer>();
487         arrayList.add(i1);
488         arrayList.add(i2);
489         mBundle.putIntegerArrayList(KEY1, arrayList);
490         ArrayList<Integer> retArrayList = mBundle.getIntegerArrayList(KEY1);
491         assertNotNull(retArrayList);
492         assertEquals(2, retArrayList.size());
493         assertEquals((Integer)i1, retArrayList.get(0));
494         assertEquals((Integer)i2, retArrayList.get(1));
495         roundtrip();
496         retArrayList = mBundle.getIntegerArrayList(KEY1);
497         assertNotNull(retArrayList);
498         assertEquals(2, retArrayList.size());
499         assertEquals((Integer)i1, retArrayList.get(0));
500         assertEquals((Integer)i2, retArrayList.get(1));
501     }
502 
503     @Test
testGetLong1()504     public void testGetLong1() {
505         final long l = 1007;
506 
507         assertEquals(0, mBundle.getLong(KEY1));
508         mBundle.putLong(KEY1, l);
509         assertEquals(l, mBundle.getLong(KEY1));
510         roundtrip();
511         assertEquals(l, mBundle.getLong(KEY1));
512     }
513 
514     @Test
testGetLong2()515     public void testGetLong2() {
516         final long l1 = 1006;
517         final long l2 = 1007;
518 
519         assertEquals(l1, mBundle.getLong(KEY1, l1));
520         mBundle.putLong(KEY1, l2);
521         assertEquals(l2, mBundle.getLong(KEY1, l2));
522         roundtrip();
523         assertEquals(l2, mBundle.getLong(KEY1, l2));
524     }
525 
526     @Test
testGetLongArray()527     public void testGetLongArray() {
528         assertNull(mBundle.getLongArray(KEY1));
529         mBundle.putLongArray(KEY1, new long[] {
530                 1006, 1007
531         });
532         long[] longArray = mBundle.getLongArray(KEY1);
533         assertEquals(1006, longArray[0]);
534         assertEquals(1007, longArray[1]);
535         roundtrip();
536         longArray = mBundle.getLongArray(KEY1);
537         assertEquals(1006, longArray[0]);
538         assertEquals(1007, longArray[1]);
539     }
540 
541     @Test
testGetParcelable()542     public void testGetParcelable() {
543         assertNull(mBundle.getParcelable(KEY1));
544         final Bundle bundle = new Bundle();
545         mBundle.putParcelable(KEY1, bundle);
546         assertTrue(bundle.equals(mBundle.getParcelable(KEY1)));
547         roundtrip();
548         assertBundleEquals(bundle, (Bundle) mBundle.getParcelable(KEY1));
549     }
550 
551     @Test
testGetParcelableTypeSafe_withMismatchingType_returnsNull()552     public void testGetParcelableTypeSafe_withMismatchingType_returnsNull() {
553         mBundle.putParcelable(KEY1, new CustomParcelable(42, "don't panic"));
554         roundtrip();
555         assertNull(mBundle.getParcelable(KEY1, Intent.class));
556         assertFalse(CustomParcelable.sDeserialized);
557     }
558 
559     @Test
testGetParcelableTypeSafe_withMatchingType_returnsObject()560     public void testGetParcelableTypeSafe_withMatchingType_returnsObject() {
561         final CustomParcelable original = new CustomParcelable(42, "don't panic");
562         mBundle.putParcelable(KEY1, original);
563         roundtrip();
564         assertEquals(original, mBundle.getParcelable(KEY1, CustomParcelable.class));
565     }
566 
567     @Test
testGetParcelableTypeSafe_withBaseType_returnsObject()568     public void testGetParcelableTypeSafe_withBaseType_returnsObject() {
569         final CustomParcelable original = new CustomParcelable(42, "don't panic");
570         mBundle.putParcelable(KEY1, original);
571         roundtrip();
572         assertEquals(original, mBundle.getParcelable(KEY1, Parcelable.class));
573     }
574 
575     // getParcelableArray should only return the ParcelableArray set by putParcelableArray
576     @Test
testGetParcelableArray()577     public void testGetParcelableArray() {
578         assertNull(mBundle.getParcelableArray(KEY1));
579         final Bundle bundle1 = new Bundle();
580         final Bundle bundle2 = new Bundle();
581         mBundle.putParcelableArray(KEY1, new Bundle[] {
582                 bundle1, bundle2
583         });
584         Parcelable[] parcelableArray = mBundle.getParcelableArray(KEY1);
585         assertEquals(2, parcelableArray.length);
586         assertTrue(bundle1.equals(parcelableArray[0]));
587         assertTrue(bundle2.equals(parcelableArray[1]));
588         roundtrip();
589         parcelableArray = mBundle.getParcelableArray(KEY1);
590         assertEquals(2, parcelableArray.length);
591         assertBundleEquals(bundle1, (Bundle) parcelableArray[0]);
592         assertBundleEquals(bundle2, (Bundle) parcelableArray[1]);
593     }
594 
595     @Test
testGetParcelableArrayTypeSafe_withMismatchingType_returnsNull()596     public void testGetParcelableArrayTypeSafe_withMismatchingType_returnsNull() {
597         mBundle.putParcelableArray(KEY1, new CustomParcelable[] {
598                 new CustomParcelable(42, "don't panic")
599         });
600         roundtrip();
601         assertNull(mBundle.getParcelableArray(KEY1, Intent.class));
602         assertFalse(CustomParcelable.sDeserialized);
603     }
604 
605     @Test
testGetParcelableArrayTypeSafe_withMatchingType_returnsObject()606     public void testGetParcelableArrayTypeSafe_withMatchingType_returnsObject() {
607         final CustomParcelable[] original = new CustomParcelable[] {
608                 new CustomParcelable(42, "don't panic"),
609                 new CustomParcelable(1961, "off we go")
610         };
611         mBundle.putParcelableArray(KEY1, original);
612         roundtrip();
613         assertArrayEquals(original, mBundle.getParcelableArray(KEY1, CustomParcelable.class));
614     }
615 
616     @Test
testGetParcelableArrayTypeSafe_withBaseType_returnsObject()617     public void testGetParcelableArrayTypeSafe_withBaseType_returnsObject() {
618         final CustomParcelable[] original = new CustomParcelable[] {
619                 new CustomParcelable(42, "don't panic"),
620                 new CustomParcelable(1961, "off we go")
621         };
622         mBundle.putParcelableArray(KEY1, original);
623         roundtrip();
624         assertArrayEquals(original, mBundle.getParcelableArray(KEY1, Parcelable.class));
625     }
626 
627     // getParcelableArrayList should only return the parcelableArrayList set by putParcelableArrayList
628     @Test
testGetParcelableArrayList()629     public void testGetParcelableArrayList() {
630         assertNull(mBundle.getParcelableArrayList(KEY1));
631         final ArrayList<Parcelable> parcelableArrayList = new ArrayList<Parcelable>();
632         final Bundle bundle1 = new Bundle();
633         final Bundle bundle2 = new Bundle();
634         parcelableArrayList.add(bundle1);
635         parcelableArrayList.add(bundle2);
636         mBundle.putParcelableArrayList(KEY1, parcelableArrayList);
637         ArrayList<Parcelable> ret = mBundle.getParcelableArrayList(KEY1);
638         assertEquals(2, ret.size());
639         assertTrue(bundle1.equals(ret.get(0)));
640         assertTrue(bundle2.equals(ret.get(1)));
641         roundtrip();
642         ret = mBundle.getParcelableArrayList(KEY1);
643         assertEquals(2, ret.size());
644         assertBundleEquals(bundle1, (Bundle) ret.get(0));
645         assertBundleEquals(bundle2, (Bundle) ret.get(1));
646     }
647 
648     @Test
testGetParcelableArrayListTypeSafe_withMismatchingType_returnsNull()649     public void testGetParcelableArrayListTypeSafe_withMismatchingType_returnsNull() {
650         final ArrayList<CustomParcelable> originalObjects = new ArrayList<>();
651         originalObjects.add(new CustomParcelable(42, "don't panic"));
652         mBundle.putParcelableArrayList(KEY1, originalObjects);
653         roundtrip();
654         assertNull(mBundle.getParcelableArrayList(KEY1, Intent.class));
655         assertFalse(CustomParcelable.sDeserialized);
656     }
657 
658     @Test
testGetParcelableArrayListTypeSafe_withMatchingType_returnsObject()659     public void testGetParcelableArrayListTypeSafe_withMatchingType_returnsObject() {
660         final ArrayList<CustomParcelable> original = new ArrayList<>();
661         original.add(new CustomParcelable(42, "don't panic"));
662         original.add(new CustomParcelable(1961, "off we go"));
663         mBundle.putParcelableArrayList(KEY1, original);
664         roundtrip();
665         assertEquals(original, mBundle.getParcelableArrayList(KEY1, CustomParcelable.class));
666     }
667 
668     @Test
testGetParcelableArrayListTypeSafe_withMismatchingTypeAndDifferentReturnType_returnsNull()669     public void testGetParcelableArrayListTypeSafe_withMismatchingTypeAndDifferentReturnType_returnsNull() {
670         final ArrayList<CustomParcelable> originalObjects = new ArrayList<>();
671         originalObjects.add(new CustomParcelable(42, "don't panic"));
672         mBundle.putParcelableArrayList(KEY1, originalObjects);
673         roundtrip();
674         ArrayList<Parcelable> result = mBundle.getParcelableArrayList(KEY1, Intent.class);
675         assertNull(result);
676         assertFalse(CustomParcelable.sDeserialized);
677     }
678 
679     @Test
testGetParcelableArrayListTypeSafe_withMatchingTypeAndDifferentReturnType__returnsObject()680     public void testGetParcelableArrayListTypeSafe_withMatchingTypeAndDifferentReturnType__returnsObject() {
681         final ArrayList<CustomParcelable> original = new ArrayList<>();
682         original.add(new CustomParcelable(42, "don't panic"));
683         original.add(new CustomParcelable(1961, "off we go"));
684         mBundle.putParcelableArrayList(KEY1, original);
685         roundtrip();
686         ArrayList<Parcelable> result = mBundle.getParcelableArrayList(KEY1, CustomParcelable.class);
687         assertEquals(original, result);
688     }
689 
690     @Test
testGetParcelableArrayListTypeSafe_withBaseType_returnsObject()691     public void testGetParcelableArrayListTypeSafe_withBaseType_returnsObject() {
692         final ArrayList<CustomParcelable> original = new ArrayList<>();
693         original.add(new CustomParcelable(42, "don't panic"));
694         original.add(new CustomParcelable(1961, "off we go"));
695         mBundle.putParcelableArrayList(KEY1, original);
696         roundtrip();
697         assertEquals(original, mBundle.getParcelableArrayList(KEY1, Parcelable.class));
698     }
699 
700     @Test
testGetSerializableTypeSafe_withMismatchingType_returnsNull()701     public void testGetSerializableTypeSafe_withMismatchingType_returnsNull() {
702         mBundle.putSerializable(KEY1, new CustomSerializable());
703         roundtrip();
704         assertNull(mBundle.getSerializable(KEY1, AnotherSerializable.class));
705         assertFalse(CustomSerializable.sDeserialized);
706     }
707 
708     @Test
testGetSerializableTypeSafe_withMatchingType_returnsObject()709     public void testGetSerializableTypeSafe_withMatchingType_returnsObject() {
710         mBundle.putSerializable(KEY1, new CustomSerializable());
711         roundtrip();
712         assertNotNull(mBundle.getSerializable(KEY1, CustomSerializable.class));
713         assertTrue(CustomSerializable.sDeserialized);
714     }
715 
716     @Test
testGetSerializableTypeSafe_withBaseType_returnsObject()717     public void testGetSerializableTypeSafe_withBaseType_returnsObject() {
718         mBundle.putSerializable(KEY1, new CustomSerializable());
719         roundtrip();
720         assertNotNull(mBundle.getSerializable(KEY1, Serializable.class));
721         assertTrue(CustomSerializable.sDeserialized);
722     }
723 
724     @Test
testGetSerializableWithString()725     public void testGetSerializableWithString() {
726         assertNull(mBundle.getSerializable(KEY1));
727         String s = "android";
728         mBundle.putSerializable(KEY1, s);
729         assertEquals(s, mBundle.getSerializable(KEY1));
730         roundtrip();
731         assertEquals(s, mBundle.getSerializable(KEY1));
732     }
733 
734     @Test
testGetSerializableWithStringArray()735     public void testGetSerializableWithStringArray() {
736         assertNull(mBundle.getSerializable(KEY1));
737         String[] strings = new String[]{"first", "last"};
738         mBundle.putSerializable(KEY1, strings);
739         assertEquals(Arrays.asList(strings),
740                 Arrays.asList((String[]) mBundle.getSerializable(KEY1)));
741         roundtrip();
742         assertEquals(Arrays.asList(strings),
743                 Arrays.asList((String[]) mBundle.getSerializable(KEY1)));
744     }
745 
746     @Test
testGetSerializableWithMultiDimensionalObjectArray()747     public void testGetSerializableWithMultiDimensionalObjectArray() {
748         assertNull(mBundle.getSerializable(KEY1));
749         Object[][] objects = new Object[][] {
750                 {"string", 1L}
751         };
752         mBundle.putSerializable(KEY1, objects);
753         assertEquals(Arrays.asList(objects[0]),
754                 Arrays.asList(((Object[][]) mBundle.getSerializable(KEY1))[0]));
755         roundtrip();
756         assertEquals(Arrays.asList(objects[0]),
757                 Arrays.asList(((Object[][]) mBundle.getSerializable(KEY1))[0]));
758     }
759 
760     @Test
testGetShort1()761     public void testGetShort1() {
762         final short s = 1007;
763 
764         assertEquals(0, mBundle.getShort(KEY1));
765         mBundle.putShort(KEY1, s);
766         assertEquals(s, mBundle.getShort(KEY1));
767         roundtrip();
768         assertEquals(s, mBundle.getShort(KEY1));
769     }
770 
771     @Test
testGetShort2()772     public void testGetShort2() {
773         final short s1 = 1006;
774         final short s2 = 1007;
775 
776         assertEquals(s1, mBundle.getShort(KEY1, s1));
777         mBundle.putShort(KEY1, s2);
778         assertEquals(s2, mBundle.getShort(KEY1, s1));
779         roundtrip();
780         assertEquals(s2, mBundle.getShort(KEY1, s1));
781     }
782 
783     @Test
testGetShortArray()784     public void testGetShortArray() {
785         final short s1 = 1006;
786         final short s2 = 1007;
787 
788         assertNull(mBundle.getShortArray(KEY1));
789         mBundle.putShortArray(KEY1, new short[] {
790                 s1, s2
791         });
792         short[] shortArray = mBundle.getShortArray(KEY1);
793         assertEquals(s1, shortArray[0]);
794         assertEquals(s2, shortArray[1]);
795         roundtrip();
796         shortArray = mBundle.getShortArray(KEY1);
797         assertEquals(s1, shortArray[0]);
798         assertEquals(s2, shortArray[1]);
799     }
800 
801     // getSparseParcelableArray should only return the SparseArray<Parcelable>
802     // set by putSparseParcelableArray
803     @Test
testGetSparseParcelableArray()804     public void testGetSparseParcelableArray() {
805         assertNull(mBundle.getSparseParcelableArray(KEY1));
806         final SparseArray<Parcelable> sparseArray = new SparseArray<Parcelable>();
807         final Bundle bundle = new Bundle();
808         final CustomParcelable custom = new CustomParcelable(42, "example");
809         sparseArray.put(1006, bundle);
810         sparseArray.put(1007, custom);
811         mBundle.putSparseParcelableArray(KEY1, sparseArray);
812         SparseArray<Parcelable> ret = mBundle.getSparseParcelableArray(KEY1);
813         assertEquals(2, ret.size());
814         assertNull(ret.get(1008));
815         assertTrue(bundle.equals(ret.get(1006)));
816         assertTrue(custom.equals(ret.get(1007)));
817         roundtrip();
818         ret = mBundle.getSparseParcelableArray(KEY1);
819         assertEquals(2, ret.size());
820         assertNull(ret.get(1008));
821         assertBundleEquals(bundle, (Bundle) ret.get(1006));
822         assertEquals(custom, (CustomParcelable) ret.get(1007));
823     }
824 
825     @Test
testGetSparseParcelableArrayTypeSafe_withMismatchingType_returnsNull()826     public void testGetSparseParcelableArrayTypeSafe_withMismatchingType_returnsNull() {
827         final SparseArray<CustomParcelable> originalObjects = new SparseArray<>();
828         originalObjects.put(42, new CustomParcelable(42, "don't panic"));
829         mBundle.putSparseParcelableArray(KEY1, originalObjects);
830         roundtrip();
831         assertNull(mBundle.getSparseParcelableArray(KEY1, Intent.class));
832         assertFalse(CustomParcelable.sDeserialized);
833     }
834 
835     @Test
testGetSparseParcelableArrayTypeSafe_withMatchingType_returnsObject()836     public void testGetSparseParcelableArrayTypeSafe_withMatchingType_returnsObject() {
837         final SparseArray<CustomParcelable> original = new SparseArray<>();
838         original.put(42, new CustomParcelable(42, "don't panic"));
839         original.put(1961, new CustomParcelable(1961, "off we go"));
840         mBundle.putSparseParcelableArray(KEY1, original);
841         roundtrip();
842         assertTrue(original.contentEquals(mBundle.getSparseParcelableArray(KEY1, CustomParcelable.class)));
843     }
844 
845     @Test
testGetSparseParcelableArrayTypeSafe_withMismatchingTypeAndDifferentReturnType_returnsNull()846     public void testGetSparseParcelableArrayTypeSafe_withMismatchingTypeAndDifferentReturnType_returnsNull() {
847         final SparseArray<CustomParcelable> originalObjects = new SparseArray<>();
848         originalObjects.put(42, new CustomParcelable(42, "don't panic"));
849         mBundle.putSparseParcelableArray(KEY1, originalObjects);
850         roundtrip();
851         SparseArray<Parcelable> result = mBundle.getSparseParcelableArray(KEY1, Intent.class);
852         assertNull(result);
853         assertFalse(CustomParcelable.sDeserialized);
854     }
855 
856     @Test
testGetSparseParcelableArrayTypeSafe_withMatchingTypeAndDifferentReturnType_returnsObject()857     public void testGetSparseParcelableArrayTypeSafe_withMatchingTypeAndDifferentReturnType_returnsObject() {
858         final SparseArray<CustomParcelable> original = new SparseArray<>();
859         original.put(42, new CustomParcelable(42, "don't panic"));
860         original.put(1961, new CustomParcelable(1961, "off we go"));
861         mBundle.putSparseParcelableArray(KEY1, original);
862         roundtrip();
863         SparseArray<Parcelable> result = mBundle.getSparseParcelableArray(KEY1,
864                 CustomParcelable.class);
865         assertTrue(original.contentEquals(result));
866     }
867 
868     @Test
testGetSparseParcelableArrayTypeSafe_withBaseType_returnsObject()869     public void testGetSparseParcelableArrayTypeSafe_withBaseType_returnsObject() {
870         final SparseArray<CustomParcelable> original = new SparseArray<>();
871         original.put(42, new CustomParcelable(42, "don't panic"));
872         original.put(1961, new CustomParcelable(1961, "off we go"));
873         mBundle.putSparseParcelableArray(KEY1, original);
874         roundtrip();
875         assertTrue(original.contentEquals(mBundle.getSparseParcelableArray(KEY1, Parcelable.class)));
876     }
877 
878     @Test
testGetSparseParcelableArrayTypeSafe_withMixedTypes_returnsObject()879     public void testGetSparseParcelableArrayTypeSafe_withMixedTypes_returnsObject() {
880         final SparseArray<Parcelable> original = new SparseArray<>();
881         original.put(42, new CustomParcelable(42, "don't panic"));
882         original.put(1961, new ComposedParcelable(21, new CustomParcelable(21, "off we go")));
883         mBundle.putSparseParcelableArray(KEY1, original);
884         roundtrip();
885         final SparseArray<Parcelable> received = mBundle.getSparseParcelableArray(KEY1, Parcelable.class);
886         assertEquals(original.size(), received.size());
887         assertEquals(original.get(42), received.get(42));
888         assertEquals((ComposedParcelable) original.get(1961),
889                 (ComposedParcelable) received.get(1961));
890     }
891 
892     @Test
testGetString()893     public void testGetString() {
894         assertNull(mBundle.getString(KEY1));
895         mBundle.putString(KEY1, "android");
896         assertEquals("android", mBundle.getString(KEY1));
897         roundtrip();
898         assertEquals("android", mBundle.getString(KEY1));
899     }
900 
901     @Test
testGetStringArray()902     public void testGetStringArray() {
903         assertNull(mBundle.getStringArray(KEY1));
904         mBundle.putStringArray(KEY1, new String[] {
905                 "one", "two", "three"
906         });
907         String[] ret = mBundle.getStringArray(KEY1);
908         assertEquals("one", ret[0]);
909         assertEquals("two", ret[1]);
910         assertEquals("three", ret[2]);
911         roundtrip();
912         ret = mBundle.getStringArray(KEY1);
913         assertEquals("one", ret[0]);
914         assertEquals("two", ret[1]);
915         assertEquals("three", ret[2]);
916     }
917 
918     // getStringArrayList should only return the StringArrayList set by putStringArrayList
919     @Test
testGetStringArrayList()920     public void testGetStringArrayList() {
921         assertNull(mBundle.getStringArrayList(KEY1));
922         final ArrayList<String> stringArrayList = new ArrayList<String>();
923         stringArrayList.add("one");
924         stringArrayList.add("two");
925         stringArrayList.add("three");
926         mBundle.putStringArrayList(KEY1, stringArrayList);
927         ArrayList<String> ret = mBundle.getStringArrayList(KEY1);
928         assertEquals(3, ret.size());
929         assertEquals("one", ret.get(0));
930         assertEquals("two", ret.get(1));
931         assertEquals("three", ret.get(2));
932         roundtrip();
933         ret = mBundle.getStringArrayList(KEY1);
934         assertEquals(3, ret.size());
935         assertEquals("one", ret.get(0));
936         assertEquals("two", ret.get(1));
937         assertEquals("three", ret.get(2));
938     }
939 
940     @Test
testKeySet()941     public void testKeySet() {
942         Set<String> setKey = mBundle.keySet();
943         assertFalse(setKey.contains("one"));
944         assertFalse(setKey.contains("two"));
945         mBundle.putBoolean("one", true);
946         mBundle.putChar("two", 't');
947         setKey = mBundle.keySet();
948         assertEquals(2, setKey.size());
949         assertTrue(setKey.contains("one"));
950         assertTrue(setKey.contains("two"));
951         assertFalse(setKey.contains("three"));
952         roundtrip();
953         setKey = mBundle.keySet();
954         assertEquals(2, setKey.size());
955         assertTrue(setKey.contains("one"));
956         assertTrue(setKey.contains("two"));
957         assertFalse(setKey.contains("three"));
958     }
959 
960     // same as hasFileDescriptors, the only difference is that describeContents
961     // return 0 if no fd and return 1 if has fd for the tested Bundle
962 
963     @Test
964     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testDescribeContents()965     public void testDescribeContents() {
966         assertTrue((mBundle.describeContents()
967                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) == 0);
968 
969         final Parcel parcel = Parcel.obtain();
970         try {
971             mBundle.putParcelable("foo", ParcelFileDescriptor.open(
972                     new File("/system"), ParcelFileDescriptor.MODE_READ_ONLY));
973         } catch (FileNotFoundException e) {
974             throw new RuntimeException("can't open /system", e);
975         }
976         assertTrue((mBundle.describeContents()
977                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0);
978         mBundle.writeToParcel(parcel, 0);
979         mBundle.clear();
980         assertTrue((mBundle.describeContents()
981                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) == 0);
982         parcel.setDataPosition(0);
983         mBundle.readFromParcel(parcel);
984         assertTrue((mBundle.describeContents()
985                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0);
986         ParcelFileDescriptor pfd = (ParcelFileDescriptor)mBundle.getParcelable("foo");
987         assertTrue((mBundle.describeContents()
988                 & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0);
989     }
990 
991     // case 1: The default bundle doesn't has FileDescriptor.
992     // case 2: The tested Bundle should has FileDescriptor
993     //  if it read data from a Parcel object, which is created with a FileDescriptor.
994     // case 3: The tested Bundle should has FileDescriptor
995     //  if put a Parcelable object, which is created with a FileDescriptor, into it.
996     @Test
997     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withParcelFdItem()998     public void testHasFileDescriptors_withParcelFdItem() {
999         assertFalse(mBundle.hasFileDescriptors());
1000 
1001         final Parcel parcel = Parcel.obtain();
1002         assertFalse(parcel.hasFileDescriptors());
1003         try {
1004             mBundle.putParcelable("foo", ParcelFileDescriptor.open(
1005                     new File("/system"), ParcelFileDescriptor.MODE_READ_ONLY));
1006         } catch (FileNotFoundException e) {
1007             throw new RuntimeException("can't open /system", e);
1008         }
1009         assertTrue(mBundle.hasFileDescriptors());
1010         mBundle.writeToParcel(parcel, 0);
1011         assertTrue(parcel.hasFileDescriptors());
1012         mBundle.clear();
1013         assertFalse(mBundle.hasFileDescriptors());
1014         parcel.setDataPosition(0);
1015         mBundle.readFromParcel(parcel);
1016         assertTrue(mBundle.hasFileDescriptors()); // Checks the parcel
1017 
1018         // Remove item to trigger deserialization and remove flag FLAG_HAS_FDS_KNOWN such that next
1019         // query triggers flag computation from lazy value
1020         mBundle.remove("unexistent");
1021         assertTrue(mBundle.hasFileDescriptors()); // Checks the lazy value
1022 
1023         // Trigger flag computation
1024         mBundle.remove("unexistent");
1025         ParcelFileDescriptor pfd = mBundle.getParcelable("foo"); // Extracts the lazy value
1026         assertTrue(mBundle.hasFileDescriptors()); // Checks the object
1027 
1028         // Now, check the lazy value returns false
1029         mBundle.clear();
1030         mBundle.putParcelable(KEY1, new CustomParcelable(13, "Tiramisu"));
1031         roundtrip();
1032         // Trigger flag computation
1033         mBundle.putParcelable("random", new CustomParcelable(13, "Tiramisu"));
1034         assertFalse(mBundle.hasFileDescriptors()); // Checks the lazy value
1035     }
1036 
1037     @Test
1038     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withParcelable()1039     public void testHasFileDescriptors_withParcelable() throws Exception {
1040         assertTrue(mBundle.isEmpty());
1041         assertFalse(mBundle.hasFileDescriptors());
1042 
1043         mBundle.putParcelable("key", ParcelFileDescriptor.dup(FileDescriptor.in));
1044         assertTrue(mBundle.hasFileDescriptors());
1045 
1046         mBundle.putParcelable("key", new CustomParcelable(13, "Tiramisu"));
1047         assertFalse(mBundle.hasFileDescriptors());
1048     }
1049 
1050     @Test
1051     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withStringArray()1052     public void testHasFileDescriptors_withStringArray() throws Exception {
1053         assertTrue(mBundle.isEmpty());
1054         assertFalse(mBundle.hasFileDescriptors());
1055 
1056         mBundle.putStringArray("key", new String[] { "string" });
1057         assertFalse(mBundle.hasFileDescriptors());
1058     }
1059 
1060     @Test
1061     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withSparseArray()1062     public void testHasFileDescriptors_withSparseArray() throws Exception {
1063         assertTrue(mBundle.isEmpty());
1064         assertFalse(mBundle.hasFileDescriptors());
1065 
1066         SparseArray<Parcelable> fdArray = new SparseArray<>();
1067         fdArray.append(0, ParcelFileDescriptor.dup(FileDescriptor.in));
1068         mBundle.putSparseParcelableArray("key", fdArray);
1069         assertTrue(mBundle.hasFileDescriptors());
1070 
1071         SparseArray<Parcelable> noFdArray = new SparseArray<>();
1072         noFdArray.append(0, new CustomParcelable(13, "Tiramisu"));
1073         mBundle.putSparseParcelableArray("key", noFdArray);
1074         assertFalse(mBundle.hasFileDescriptors());
1075 
1076         SparseArray<Parcelable> emptyArray = new SparseArray<>();
1077         mBundle.putSparseParcelableArray("key", emptyArray);
1078         assertFalse(mBundle.hasFileDescriptors());
1079     }
1080 
1081     @Test
1082     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withParcelableArray()1083     public void testHasFileDescriptors_withParcelableArray() throws Exception {
1084         assertTrue(mBundle.isEmpty());
1085         assertFalse(mBundle.hasFileDescriptors());
1086 
1087         mBundle.putParcelableArray("key",
1088                 new Parcelable[] { ParcelFileDescriptor.dup(FileDescriptor.in) });
1089         assertTrue(mBundle.hasFileDescriptors());
1090 
1091         mBundle.putParcelableArray("key",
1092                 new Parcelable[] { new CustomParcelable(13, "Tiramisu") });
1093         assertFalse(mBundle.hasFileDescriptors());
1094     }
1095 
1096     @Test
1097     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptorsOnNullValuedCollection()1098     public void testHasFileDescriptorsOnNullValuedCollection() {
1099         assertFalse(mBundle.hasFileDescriptors());
1100 
1101         mBundle.putParcelableArray("foo", new Parcelable[1]);
1102         assertFalse(mBundle.hasFileDescriptors());
1103         mBundle.clear();
1104 
1105         SparseArray<Parcelable> sparseArray = new SparseArray<Parcelable>();
1106         sparseArray.put(0, null);
1107         mBundle.putSparseParcelableArray("bar", sparseArray);
1108         assertFalse(mBundle.hasFileDescriptors());
1109         mBundle.clear();
1110 
1111         ArrayList<Parcelable> arrayList = new ArrayList<Parcelable>();
1112         arrayList.add(null);
1113         mBundle.putParcelableArrayList("baz", arrayList);
1114         assertFalse(mBundle.hasFileDescriptors());
1115         mBundle.clear();
1116     }
1117 
1118     @SuppressWarnings("unchecked")
1119     @Test
1120     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withNestedContainers()1121     public void testHasFileDescriptors_withNestedContainers() throws IOException {
1122         // Purposely omitting generic types here, this is still "valid" app code after all.
1123         ArrayList nested = new ArrayList(
1124                 Arrays.asList(Arrays.asList(ParcelFileDescriptor.dup(FileDescriptor.in))));
1125         mBundle.putParcelableArrayList("list", nested);
1126         assertTrue(mBundle.hasFileDescriptors());
1127 
1128         roundtrip(/* parcel */ false);
1129         assertTrue(mBundle.hasFileDescriptors());
1130 
1131         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1132         mBundle.remove("unexistent"); // Removes cached value (removes FLAG_HAS_FDS_KNOWN)
1133         assertTrue(mBundle.hasFileDescriptors()); // Checks lazy value
1134     }
1135 
1136     @Test
1137     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withOriginalParcelContainingFdButNotItems()1138     public void testHasFileDescriptors_withOriginalParcelContainingFdButNotItems() throws IOException {
1139         mBundle.putParcelable("fd", ParcelFileDescriptor.dup(FileDescriptor.in));
1140         mBundle.putParcelable("parcelable", new CustomParcelable(13, "Tiramisu"));
1141         assertTrue(mBundle.hasFileDescriptors());
1142 
1143         roundtrip(/* parcel */ false);
1144         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1145         assertTrue(mBundle.hasFileDescriptors());
1146         mBundle.remove("fd");
1147 
1148         // Will check the item's specific range in the original parcel
1149         assertFalse(mBundle.hasFileDescriptors());
1150     }
1151 
1152     @Test
1153     @IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
testHasFileDescriptors_withOriginalParcelAndItemsContainingFd()1154     public void testHasFileDescriptors_withOriginalParcelAndItemsContainingFd() throws IOException {
1155         mBundle.putParcelable("fd", ParcelFileDescriptor.dup(FileDescriptor.in));
1156         mBundle.putParcelable("parcelable", new CustomParcelable(13, "Tiramisu"));
1157         assertTrue(mBundle.hasFileDescriptors());
1158 
1159         roundtrip(/* parcel */ false);
1160         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1161         assertTrue(mBundle.hasFileDescriptors());
1162         mBundle.remove("parcelable");
1163 
1164         // Will check the item's specific range in the original parcel
1165         assertTrue(mBundle.hasFileDescriptors());
1166     }
1167 
1168     @Test
testSetClassLoader()1169     public void testSetClassLoader() {
1170         mBundle.setClassLoader(new MockClassLoader());
1171     }
1172 
1173     // Write the bundle(A) to a parcel(B), and then create a bundle(C) from B.
1174     // C should be same as A.
1175     @Test
testWriteToParcel()1176     public void testWriteToParcel() {
1177         final String li = "Bruce Li";
1178 
1179         mBundle.putString(KEY1, li);
1180         final Parcel parcel = Parcel.obtain();
1181         mBundle.writeToParcel(parcel, 0);
1182         parcel.setDataPosition(0);
1183         final Bundle bundle = Bundle.CREATOR.createFromParcel(parcel);
1184         assertEquals(li, bundle.getString(KEY1));
1185     }
1186 
1187     // test the size should be right after add/remove key-value pair of the Bundle.
1188     @Test
testSize()1189     public void testSize() {
1190         assertEquals(0, mBundle.size());
1191         mBundle.putBoolean("one", true);
1192         assertEquals(1, mBundle.size());
1193 
1194         mBundle.putBoolean("two", true);
1195         assertEquals(2, mBundle.size());
1196 
1197         mBundle.putBoolean("three", true);
1198         assertEquals(3, mBundle.size());
1199 
1200         mBundle.putBoolean("four", true);
1201         mBundle.putBoolean("five", true);
1202         assertEquals(5, mBundle.size());
1203         mBundle.remove("six");
1204         assertEquals(5, mBundle.size());
1205 
1206         mBundle.remove("one");
1207         assertEquals(4, mBundle.size());
1208         mBundle.remove("one");
1209         assertEquals(4, mBundle.size());
1210 
1211         mBundle.remove("two");
1212         assertEquals(3, mBundle.size());
1213 
1214         mBundle.remove("three");
1215         mBundle.remove("four");
1216         mBundle.remove("five");
1217         assertEquals(0, mBundle.size());
1218     }
1219 
1220     // The return value of toString() should not be null.
1221     @Test
testToString()1222     public void testToString() {
1223         assertNotNull(mBundle.toString());
1224         mBundle.putString("foo", "this test is so stupid");
1225         assertNotNull(mBundle.toString());
1226     }
1227 
1228     // The tested Bundle should hold mappings from the given after putAll be invoked.
1229     @Test
testPutAll()1230     public void testPutAll() {
1231         assertEquals(0, mBundle.size());
1232 
1233         final Bundle map = new Bundle();
1234         map.putBoolean(KEY1, true);
1235         assertEquals(1, map.size());
1236         mBundle.putAll(map);
1237         assertEquals(1, mBundle.size());
1238     }
1239 
roundtrip()1240     private void roundtrip() {
1241         roundtrip(/* parcel */ true);
1242     }
1243 
roundtrip(boolean parcel)1244     private void roundtrip(boolean parcel) {
1245         mBundle = roundtrip(mBundle, parcel);
1246     }
1247 
roundtrip(Bundle bundle)1248     private Bundle roundtrip(Bundle bundle) {
1249         return roundtrip(bundle, /* parcel */ true);
1250     }
1251 
roundtrip(Bundle bundle, boolean parcel)1252     private Bundle roundtrip(Bundle bundle, boolean parcel) {
1253         Parcel p = Parcel.obtain();
1254         bundle.writeToParcel(p, 0);
1255         if (parcel) {
1256             p = roundtripParcel(p);
1257         }
1258         p.setDataPosition(0);
1259         return p.readBundle(bundle.getClassLoader());
1260     }
1261 
roundtripParcel(Parcel out)1262     private Parcel roundtripParcel(Parcel out) {
1263         byte[] buf = out.marshall();
1264         Parcel in = Parcel.obtain();
1265         in.unmarshall(buf, 0, buf.length);
1266         in.setDataPosition(0);
1267         return in;
1268     }
1269 
assertBundleEquals(Bundle expected, Bundle observed)1270     private void assertBundleEquals(Bundle expected, Bundle observed) {
1271         assertEquals(expected.size(), observed.size());
1272         for (String key : expected.keySet()) {
1273             assertEquals(expected.get(key), observed.get(key));
1274         }
1275     }
1276 
assertSpannableEquals(Spannable expected, CharSequence observed)1277     private void assertSpannableEquals(Spannable expected, CharSequence observed) {
1278         final Spannable observedSpan = (Spannable) observed;
1279         assertEquals(expected.toString(), observed.toString());
1280         Object[] expectedSpans = expected.getSpans(0, expected.length(), Object.class);
1281         Object[] observedSpans = observedSpan.getSpans(0, observedSpan.length(), Object.class);
1282         assertEquals(expectedSpans.length, observedSpans.length);
1283         for (int i = 0; i < expectedSpans.length; i++) {
1284             // Can't compare values of arbitrary objects
1285             assertEquals(expectedSpans[i].getClass(), observedSpans[i].getClass());
1286         }
1287     }
1288 
1289     @Test
1290     @IgnoreUnderRavenwood
testHasFileDescriptor()1291     public void testHasFileDescriptor() throws Exception {
1292         final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
1293         try {
1294             final ParcelFileDescriptor fd = pipe[0];
1295 
1296             assertNotHaveFd(Bundle.EMPTY);
1297             assertNotHaveFd(new Bundle());
1298 
1299             assertNotHaveFd(buildBundle("a", 1));
1300 
1301             assertHasFd(buildBundle("a", 1, fd));
1302             assertHasFd(buildBundle("a", 1, new Parcelable[]{fd}));
1303             assertHasFd(buildBundle("a", 1, buildBundle(new Parcelable[]{fd})));
1304             assertNotHaveFd(buildBundle("a", 1, buildBundle(1)));
1305 
1306             Bundle nested1 = buildBundle(fd, buildBundle(1));
1307             assertHasFd(nested1); // Outer bundle has an FD.
1308             assertNotHaveFd(nested1.getParcelable("key-1")); // But inner bundle doesn't.
1309 
1310             Bundle nested2 = buildBundle(1, buildBundle(fd));
1311             assertHasFd(nested2);
1312             assertHasFd(nested2.getParcelable("key-1"));
1313 
1314             // More tricky case.  Create a parcel with mixed objects.
1315             Parcel p = Parcel.obtain();
1316             p.writeParcelable(fd, 0);
1317             p.writeInt(123);
1318             p.writeParcelable(buildBundle(1), 0);
1319 
1320             // Now the parcel has an FD.
1321             p.setDataPosition(0);
1322             assertTrue(p.hasFileDescriptors());
1323 
1324             // Note even though the entire parcel has an FD, the inner bundle doesn't.
1325             assertEquals(ParcelFileDescriptor.class,
1326                     p.readParcelable(getClass().getClassLoader()).getClass());
1327             assertEquals(123, p.readInt());
1328             assertNotHaveFd(p.readParcelable(Bundle.class.getClassLoader()));
1329         } finally {
1330             pipe[0].close();
1331             pipe[1].close();
1332         }
1333     }
1334 
1335     @Test
testBundleLengthNotAlignedByFour()1336     public void testBundleLengthNotAlignedByFour() {
1337         mBundle.putBoolean(KEY1, true);
1338         assertEquals(1, mBundle.size());
1339         Parcel p = Parcel.obtain();
1340         final int lengthPos = p.dataPosition();
1341         mBundle.writeToParcel(p, 0);
1342         p.setDataPosition(lengthPos);
1343         final int length = p.readInt();
1344         assertTrue(length != 0);
1345         assertTrue(length % 4 == 0);
1346         // Corrupt the bundle length so it is not aligned by 4.
1347         p.setDataPosition(lengthPos);
1348         p.writeInt(length - 1);
1349         p.setDataPosition(0);
1350         final Bundle b = new Bundle();
1351         try {
1352             b.readFromParcel(p);
1353             fail("Failed to get an IllegalStateException");
1354         } catch (IllegalStateException e) {
1355             // Expect IllegalStateException here.
1356         }
1357     }
1358 
1359     @Test
testGetCustomParcelable()1360     public void testGetCustomParcelable() {
1361         Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
1362         mBundle.putParcelable(KEY1, parcelable);
1363         assertEquals(parcelable, mBundle.getParcelable(KEY1));
1364         assertEquals(1, mBundle.size());
1365         roundtrip();
1366         assertNotSame(parcelable, mBundle.getParcelable(KEY1));
1367         assertEquals(parcelable, mBundle.getParcelable(KEY1));
1368         assertEquals(1, mBundle.size());
1369     }
1370 
1371     @Test
testGetNestedParcelable()1372     public void testGetNestedParcelable() {
1373         Parcelable nested = new CustomParcelable(13, "Tiramisu");
1374         ComposedParcelable parcelable = new ComposedParcelable(26, nested);
1375         mBundle.putParcelable(KEY1, parcelable);
1376         assertEquals(parcelable, mBundle.getParcelable(KEY1));
1377         assertEquals(1, mBundle.size());
1378         roundtrip();
1379         ComposedParcelable reconstructed = mBundle.getParcelable(KEY1);
1380         assertNotSame(parcelable, reconstructed);
1381         assertEquals(parcelable, reconstructed);
1382         assertNotSame(nested, reconstructed.parcelable);
1383         assertEquals(nested, reconstructed.parcelable);
1384         assertEquals(1, mBundle.size());
1385     }
1386 
1387     @Test
testItemDeserializationIndependence()1388     public void testItemDeserializationIndependence() {
1389         Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
1390         Parcelable bomb = new CustomParcelable(13, "Tiramisu").setThrowsDuringDeserialization(true);
1391         mBundle.putParcelable(KEY1, parcelable);
1392         mBundle.putParcelable(KEY2, bomb);
1393         assertEquals(parcelable, mBundle.getParcelable(KEY1));
1394         assertEquals(bomb, mBundle.getParcelable(KEY2));
1395         assertEquals(2, mBundle.size());
1396         roundtrip();
1397         assertEquals(2, mBundle.size());
1398         Parcelable reParcelable = mBundle.getParcelable(KEY1);
1399         // Passed if it didn't throw
1400         assertNotSame(parcelable, reParcelable);
1401         assertEquals(parcelable, reParcelable);
1402         assertThrows(RuntimeException.class, () -> mBundle.getParcelable(KEY2));
1403         assertEquals(2, mBundle.size());
1404     }
1405 
1406     @Test
testLazyValueReserialization()1407     public void testLazyValueReserialization() {
1408         Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
1409         mBundle.putParcelable(KEY1, parcelable);
1410         mBundle.putString(KEY2, "value");
1411         roundtrip();
1412         assertEquals("value", mBundle.getString(KEY2));
1413         // Since we haven't retrieved KEY1, its value is still a lazy value inside bundle
1414         roundtrip();
1415         assertEquals(parcelable, mBundle.getParcelable(KEY1));
1416         assertEquals("value", mBundle.getString(KEY2));
1417     }
1418 
1419     @Test
testPutAll_withLazyValues()1420     public void testPutAll_withLazyValues() {
1421         Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
1422         mBundle.putParcelable(KEY1, parcelable);
1423         roundtrip();
1424         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1425         Bundle copy = new Bundle();
1426         copy.putAll(mBundle);
1427         assertEquals(parcelable, copy.getParcelable(KEY1));
1428         // Here we're verifying that LazyValue caches the deserialized object, hence they are the
1429         // same instance
1430         assertSame(copy.getParcelable(KEY1), mBundle.getParcelable(KEY1));
1431         assertEquals(1, copy.size());
1432     }
1433 
1434     @Test
testDeepCopy_withLazyValues()1435     public void testDeepCopy_withLazyValues() {
1436         Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
1437         mBundle.putParcelable(KEY1, parcelable);
1438         roundtrip();
1439         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1440         Bundle copy = mBundle.deepCopy();
1441         assertEquals(parcelable, copy.getParcelable(KEY1));
1442         // Here we're verifying that LazyValue caches the deserialized object, hence they are the
1443         // same instance
1444         assertSame(copy.getParcelable(KEY1), mBundle.getParcelable(KEY1));
1445         assertEquals(1, copy.size());
1446     }
1447 
1448     @Test
testDeepCopy_withNestedParcelable()1449     public void testDeepCopy_withNestedParcelable() {
1450         Parcelable nested = new CustomParcelable(13, "Tiramisu");
1451         ComposedParcelable parcelable = new ComposedParcelable(26, nested);
1452         mBundle.putParcelable(KEY1, parcelable);
1453         roundtrip();
1454         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1455         Bundle copy = mBundle.deepCopy();
1456         ComposedParcelable reconstructed = copy.getParcelable(KEY1);
1457         assertEquals(parcelable, reconstructed);
1458         assertSame(copy.getParcelable(KEY1), mBundle.getParcelable(KEY1));
1459         assertEquals(nested, reconstructed.parcelable);
1460         assertEquals(1, copy.size());
1461     }
1462 
1463     @Test
testDeepCopy_withNestedBundleAndLazyValues()1464     public void testDeepCopy_withNestedBundleAndLazyValues() {
1465         Parcelable parcelable = new CustomParcelable(13, "Tiramisu");
1466         Bundle inner = new Bundle();
1467         inner.putParcelable(KEY1, parcelable);
1468         inner = roundtrip(inner);
1469         inner.setClassLoader(getClass().getClassLoader());
1470         inner.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1471         mBundle.putParcelable(KEY1, inner);
1472         Bundle copy = mBundle.deepCopy();
1473         assertEquals(parcelable, copy.getBundle(KEY1).getParcelable(KEY1));
1474         assertNotSame(mBundle.getBundle(KEY1), copy.getBundle(KEY1));
1475         assertSame(mBundle.getBundle(KEY1).getParcelable(KEY1),
1476                 copy.getBundle(KEY1).getParcelable(KEY1));
1477         assertEquals(1, copy.getBundle(KEY1).size());
1478         assertEquals(1, copy.size());
1479     }
1480 
1481     @Test
testGetParcelable_isLazy()1482     public void testGetParcelable_isLazy() {
1483         mBundle.putParcelable(KEY1, new CustomParcelable(13, "Tiramisu"));
1484         roundtrip();
1485         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1486         assertThat(CustomParcelable.sDeserialized).isFalse();
1487         mBundle.getParcelable(KEY1);
1488         assertThat(CustomParcelable.sDeserialized).isTrue();
1489     }
1490 
1491     @Test
testGetParcelableArray_isLazy()1492     public void testGetParcelableArray_isLazy() {
1493         mBundle.putParcelableArray(KEY1, new Parcelable[] {new CustomParcelable(13, "Tiramisu")});
1494         roundtrip();
1495         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1496         assertThat(CustomParcelable.sDeserialized).isFalse();
1497         mBundle.getParcelableArray(KEY1);
1498         assertThat(CustomParcelable.sDeserialized).isTrue();
1499     }
1500 
1501     @Test
testGetParcelableArrayList_isLazy()1502     public void testGetParcelableArrayList_isLazy() {
1503         mBundle.putParcelableArrayList(KEY1,
1504                 new ArrayList<>(singletonList(new CustomParcelable(13, "Tiramisu"))));
1505         roundtrip();
1506         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1507         assertThat(CustomParcelable.sDeserialized).isFalse();
1508         mBundle.getParcelableArrayList(KEY1);
1509         assertThat(CustomParcelable.sDeserialized).isTrue();
1510     }
1511 
1512     @Test
testGetSparseParcelableArray_isLazy()1513     public void testGetSparseParcelableArray_isLazy() {
1514         SparseArray<Parcelable> container = new SparseArray<>();
1515         container.put(0, new CustomParcelable(13, "Tiramisu"));
1516         mBundle.putSparseParcelableArray(KEY1, container);
1517         roundtrip();
1518         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1519         assertThat(CustomParcelable.sDeserialized).isFalse();
1520         mBundle.getSparseParcelableArray(KEY1);
1521         assertThat(CustomParcelable.sDeserialized).isTrue();
1522     }
1523 
1524     @Test
testGetSerializable_isLazy()1525     public void testGetSerializable_isLazy() {
1526         mBundle.putSerializable(KEY1, new CustomSerializable());
1527         roundtrip();
1528         mBundle.isEmpty(); // Triggers partial deserialization (leaving lazy values)
1529         assertThat(CustomSerializable.sDeserialized).isFalse();
1530         mBundle.getSerializable(KEY1);
1531         assertThat(CustomSerializable.sDeserialized).isTrue();
1532     }
1533 
1534     public static class CustomSerializable implements Serializable {
1535         public static boolean sDeserialized = false;
1536 
readObject(ObjectInputStream in)1537         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1538             in.defaultReadObject();
1539             sDeserialized = true;
1540         }
1541     }
1542 
1543     public static class AnotherSerializable implements Serializable {
1544     }
1545 
1546     public static class CustomParcelable implements Parcelable {
1547         public static boolean sDeserialized = false;
1548 
1549         public final int integer;
1550         public final String string;
1551         public boolean throwsDuringDeserialization;
1552 
CustomParcelable(int integer, String string)1553         public CustomParcelable(int integer, String string) {
1554             this.integer = integer;
1555             this.string = string;
1556         }
1557 
CustomParcelable(Parcel in)1558         protected CustomParcelable(Parcel in) {
1559             integer = in.readInt();
1560             string = in.readString();
1561             throwsDuringDeserialization = in.readBoolean();
1562             if (throwsDuringDeserialization) {
1563                 throw new RuntimeException();
1564             }
1565             sDeserialized = true;
1566         }
1567 
setThrowsDuringDeserialization( boolean throwsDuringDeserialization)1568         public CustomParcelable setThrowsDuringDeserialization(
1569                 boolean throwsDuringDeserialization) {
1570             this.throwsDuringDeserialization = throwsDuringDeserialization;
1571             return this;
1572         }
1573 
1574         @Override
describeContents()1575         public int describeContents() {
1576             return 0;
1577         }
1578 
1579         @Override
writeToParcel(Parcel out, int flags)1580         public void writeToParcel(Parcel out, int flags) {
1581             out.writeInt(integer);
1582             out.writeString(string);
1583             out.writeBoolean(throwsDuringDeserialization);
1584         }
1585 
1586         @Override
equals(Object other)1587         public boolean equals(Object other) {
1588             if (this == other) {
1589                 return true;
1590             }
1591             if (!(other instanceof CustomParcelable)) {
1592                 return false;
1593             }
1594             CustomParcelable that = (CustomParcelable) other;
1595             return integer == that.integer
1596                     && throwsDuringDeserialization == that.throwsDuringDeserialization
1597                     && string.equals(that.string);
1598         }
1599 
1600         @Override
hashCode()1601         public int hashCode() {
1602             return Objects.hash(integer, string, throwsDuringDeserialization);
1603         }
1604 
1605         public static final Creator<CustomParcelable> CREATOR = new Creator<CustomParcelable>() {
1606             @Override
1607             public CustomParcelable createFromParcel(Parcel in) {
1608                 return new CustomParcelable(in);
1609             }
1610             @Override
1611             public CustomParcelable[] newArray(int size) {
1612                 return new CustomParcelable[size];
1613             }
1614         };
1615     }
1616 
1617     public static class ComposedParcelable implements Parcelable {
1618         public final int integer;
1619         public final Parcelable parcelable;
1620 
ComposedParcelable(int integer, Parcelable parcelable)1621         public ComposedParcelable(int integer, Parcelable parcelable) {
1622             this.integer = integer;
1623             this.parcelable = parcelable;
1624         }
1625 
ComposedParcelable(Parcel in)1626         protected ComposedParcelable(Parcel in) {
1627             integer = in.readInt();
1628             parcelable = in.readParcelable(getClass().getClassLoader());
1629         }
1630 
1631         @Override
describeContents()1632         public int describeContents() {
1633             return 0;
1634         }
1635 
1636         @Override
writeToParcel(Parcel out, int flags)1637         public void writeToParcel(Parcel out, int flags) {
1638             out.writeInt(integer);
1639             out.writeParcelable(parcelable, flags);
1640         }
1641 
1642         @Override
equals(Object other)1643         public boolean equals(Object other) {
1644             if (this == other) {
1645                 return true;
1646             }
1647             if (!(other instanceof ComposedParcelable)) {
1648                 return false;
1649             }
1650             ComposedParcelable that = (ComposedParcelable) other;
1651             return integer == that.integer && Objects.equals(parcelable, that.parcelable);
1652         }
1653 
1654         @Override
hashCode()1655         public int hashCode() {
1656             return Objects.hash(integer, parcelable);
1657         }
1658 
1659         public static final Creator<ComposedParcelable> CREATOR =
1660                 new Creator<ComposedParcelable>() {
1661                     @Override
1662                     public ComposedParcelable createFromParcel(Parcel in) {
1663                         return new ComposedParcelable(in);
1664                     }
1665                     @Override
1666                     public ComposedParcelable[] newArray(int size) {
1667                         return new ComposedParcelable[size];
1668                     }
1669                 };
1670     }
1671 
1672     /** Create a Bundle with values, with autogenerated keys. */
buildBundle(Object... values)1673     private static Bundle buildBundle(Object... values) {
1674         final Bundle result = new Bundle();
1675 
1676         for (int i = 0; i < values.length; i++) {
1677             final String key = "key-" + i;
1678 
1679             final Object value = values[i];
1680             if (value == null) {
1681                 result.putString(key, null);
1682 
1683             } else if (value instanceof String) {
1684                 result.putString(key, (String) value);
1685 
1686             } else if (value instanceof Integer) {
1687                 result.putInt(key, (Integer) value);
1688 
1689             } else if (value instanceof Parcelable) {
1690                 result.putParcelable(key, (Parcelable) value);
1691 
1692             } else if (value instanceof Parcelable[]) {
1693                 result.putParcelableArray(key, (Parcelable[]) value);
1694 
1695             } else {
1696                 fail("Unsupported value type: " + value.getClass());
1697             }
1698         }
1699         return result;
1700     }
1701 
cloneBundle(Bundle b)1702     private static Bundle cloneBundle(Bundle b) {
1703         return new Bundle(b);
1704     }
1705 
cloneBundleViaParcel(Bundle b)1706     private static Bundle cloneBundleViaParcel(Bundle b) {
1707         final Parcel p = Parcel.obtain();
1708         try {
1709             p.writeParcelable(b, 0);
1710 
1711             p.setDataPosition(0);
1712 
1713             return p.readParcelable(Bundle.class.getClassLoader());
1714         } finally {
1715             p.recycle();
1716         }
1717     }
1718 
assertHasFd(Bundle b)1719     private static void assertHasFd(Bundle b) {
1720         assertTrue(b.hasFileDescriptors());
1721 
1722         // Make sure cloned ones have the same result.
1723         assertTrue(cloneBundle(b).hasFileDescriptors());
1724         assertTrue(cloneBundleViaParcel(b).hasFileDescriptors());
1725     }
1726 
assertNotHaveFd(Bundle b)1727     private static void assertNotHaveFd(Bundle b) {
1728         assertFalse(b.hasFileDescriptors());
1729 
1730         // Make sure cloned ones have the same result.
1731         assertFalse(cloneBundle(b).hasFileDescriptors());
1732         assertFalse(cloneBundleViaParcel(b).hasFileDescriptors());
1733     }
1734 
1735     class MockClassLoader extends ClassLoader {
MockClassLoader()1736         MockClassLoader() {
1737             super();
1738         }
1739     }
1740 
uncheck(Callable<T> runnable)1741     private static <T> T uncheck(Callable<T> runnable) {
1742         try {
1743             return runnable.call();
1744         } catch (Exception e) {
1745             throw new AssertionError(e);
1746         }
1747     }
1748 }
1749