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