1 package com.xtremelabs.robolectric.shadows;
2 
3 import static com.xtremelabs.robolectric.Robolectric.shadowOf;
4 
5 import android.os.Bundle;
6 import android.os.Parcel;
7 import android.os.Parcelable;
8 import android.text.TextUtils;
9 import android.util.Log;
10 import android.util.Pair;
11 
12 import com.xtremelabs.robolectric.Robolectric;
13 import com.xtremelabs.robolectric.bytecode.ShadowWrangler;
14 import com.xtremelabs.robolectric.internal.Implementation;
15 import com.xtremelabs.robolectric.internal.Implements;
16 import com.xtremelabs.robolectric.internal.RealObject;
17 
18 import java.lang.reflect.Field;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 
25 @Implements(Parcel.class)
26 @SuppressWarnings("unchecked")
27 public class ShadowParcel {
28 
29     private static final int VAL_NULL = -1;
30     private static final int VAL_STRING = 0;
31     private static final int VAL_INTEGER = 1;
32     private static final int VAL_MAP = 2;
33     private static final int VAL_BUNDLE = 3;
34     private static final int VAL_PARCELABLE = 4;
35     private static final int VAL_SHORT = 5;
36     private static final int VAL_LONG = 6;
37     private static final int VAL_FLOAT = 7;
38     private static final int VAL_DOUBLE = 8;
39     private static final int VAL_BOOLEAN = 9;
40     private static final int VAL_CHARSEQUENCE = 10;
41     private static final int VAL_LIST = 11;
42     private static final int VAL_BYTEARRAY = 13;
43     private static final int VAL_STRINGARRAY = 14;
44     private static final int VAL_PARCELABLEARRAY = 16;
45     private static final int VAL_OBJECTARRAY = 17;
46     private static final int VAL_INTARRAY = 18;
47     private static final int VAL_LONGARRAY = 19;
48     private static final int VAL_BYTE = 20;
49     private static final int VAL_BOOLEANARRAY = 23;
50     private static final int VAL_CHARSEQUENCEARRAY = 24;
51 
52     private final ArrayList<Pair<Integer, ?>> parcelData = new ArrayList<Pair<Integer, ?>>();
53     private int index = 0;
54 
55     @RealObject
56     private Parcel realParcel;
57 
58     @Implementation
obtain()59     public static Parcel obtain() {
60         return Robolectric.newInstanceOf(Parcel.class);
61     }
62 
63     @Implementation
dataAvail()64     public int dataAvail() {
65         return dataSize() - dataPosition();
66     }
67 
68     @Implementation
dataPosition()69     public int dataPosition() {
70         return calculateSizeToIndex(index);
71     }
72 
73     @Implementation
dataSize()74     public int dataSize() {
75         return calculateSizeToIndex(parcelData.size());
76     }
77 
78     @Implementation
dataCapacity()79     public int dataCapacity() {
80         return dataSize();
81     }
82 
83     @Implementation
setDataPosition(int pos)84     public void setDataPosition(int pos) {
85         index = calculateIndexFromSizePosition(pos);
86     }
87 
calculateSizeToIndex(int index)88     private int calculateSizeToIndex(int index) {
89         int size = 0;
90         for (int i = 0; i < index; i++) {
91             size += parcelData.get(i).first;
92         }
93         return size;
94     }
95 
calculateIndexFromSizePosition(int pos)96     private int calculateIndexFromSizePosition(int pos) {
97         int size = 0;
98         for (int i = 0; i < parcelData.size(); i++) {
99             if (size >= pos) {
100                 return i;
101             }
102             size += parcelData.get(i).first;
103         }
104         return parcelData.size();
105     }
106 
107     @Implementation
writeString(String str)108     public void writeString(String str) {
109         if (str == null) {
110             writeInt(-1);
111         } else {
112             writeInt(str.length());
113             addValueToList(Pair.create(str.length(), str));
114         }
115     }
116 
117     @Implementation
readString()118     public String readString() {
119         int N = readInt();
120         if (N < 0) {
121             return null;
122         } else {
123             return readValueFromList(null);
124         }
125     }
126 
127     @Implementation
readCharSequence()128     public CharSequence readCharSequence() {
129         return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(realParcel);
130     }
131 
132     @Implementation
writeCharSequence(CharSequence val)133     public void writeCharSequence(CharSequence val) {
134         TextUtils.writeToParcel(val, realParcel, 0);
135     }
136 
137     @Implementation
writeInt(int i)138     public void writeInt(int i) {
139         addValueToList(Pair.create(Integer.SIZE / 8, i));
140     }
141 
142     @Implementation
readInt()143     public int readInt() {
144         return readValueFromList(0);
145     }
146 
147     @Implementation
writeLong(long i)148     public void writeLong(long i) {
149         addValueToList(Pair.create(Long.SIZE / 8, i));
150     }
151 
152     @Implementation
readLong()153     public long readLong() {
154         return readValueFromList((long) 0);
155     }
156 
157     @Implementation
writeFloat(float f)158     public void writeFloat(float f) {
159         addValueToList(Pair.create(Float.SIZE / 8, f));
160     }
161 
162     @Implementation
readFloat()163     public float readFloat() {
164         return readValueFromList((float) 0);
165     }
166 
167     @Implementation
writeDouble(double f)168     public void writeDouble(double f) {
169         addValueToList(Pair.create(Double.SIZE / 8, f));
170     }
171 
172     @Implementation
readDouble()173     public double readDouble() {
174         return readValueFromList((double) 0);
175     }
176 
writeBoolean(boolean b)177     public void writeBoolean(boolean b) {
178         addValueToList(Pair.create(1, b));
179     }
180 
readBoolean()181     public boolean readBoolean() {
182         return readValueFromList(false);
183     }
184 
writeChar(char c)185     public void writeChar(char c) {
186         addValueToList(Pair.create(Character.SIZE / 8, c));
187     }
188 
readChar()189     public char readChar() {
190         return readValueFromList((char) 0);
191     }
192 
193     @Implementation
194     @SuppressWarnings("unchecked")
writeByte(byte b)195     public void writeByte(byte b) {
196         addValueToList(Pair.create(Byte.SIZE / 8, b));
197     }
198 
199     @Implementation
readByte()200     public byte readByte() {
201         return readValueFromList((byte) 0);
202     }
203 
204     @Implementation
readBooleanArray(boolean[] val)205     public void readBooleanArray(boolean[] val) {
206         int N = readInt();
207         if (val.length != N)
208             throw new RuntimeException("bad array lengths");
209         for (int i = 0; i < val.length; i++) {
210             val[i] = readBoolean();
211         }
212     }
213 
214     @Implementation
writeBooleanArray(boolean[] val)215     public void writeBooleanArray(boolean[] val) {
216         if (val == null) {
217             writeInt(-1);
218             return;
219         }
220         writeInt(val.length);
221         for (boolean b : val)
222             writeBoolean(b);
223     }
224 
225     @Implementation
createBooleanArray()226     public boolean[] createBooleanArray() {
227         int N = readInt();
228         if (N < 0) {
229             return null;
230         }
231         boolean[] val = new boolean[N];
232         for (int i = 0; i < val.length; i++) {
233             val[i] = readBoolean();
234         }
235         return val;
236     }
237 
238     @Implementation
readCharArray(char[] val)239     public void readCharArray(char[] val) {
240         int N = readInt();
241         if (val.length != N)
242             throw new RuntimeException("bad array lengths");
243         for (int i = 0; i < val.length; i++) {
244             val[i] = readChar();
245         }
246     }
247 
248     @Implementation
writeCharArray(char[] val)249     public void writeCharArray(char[] val) {
250         if (val == null) {
251             writeInt(-1);
252             return;
253         }
254         writeInt(val.length);
255         for (char b : val)
256             writeChar(b);
257     }
258 
259     @Implementation
createCharArray()260     public char[] createCharArray() {
261         int N = readInt();
262         if (N < 0) {
263             return null;
264         }
265         char[] val = new char[N];
266         for (int i = 0; i < val.length; i++) {
267             val[i] = readChar();
268         }
269         return val;
270     }
271 
272     @Implementation
readFloatArray(float[] val)273     public void readFloatArray(float[] val) {
274         int N = readInt();
275         if (val.length != N)
276             throw new RuntimeException("bad array lengths");
277         for (int i = 0; i < val.length; i++) {
278             val[i] = readFloat();
279         }
280     }
281 
282     @Implementation
writeFloatArray(float[] val)283     public void writeFloatArray(float[] val) {
284         if (val == null) {
285             writeInt(-1);
286             return;
287         }
288         writeInt(val.length);
289         for (float f : val)
290             writeFloat(f);
291     }
292 
293     @Implementation
createFloatArray()294     public float[] createFloatArray() {
295         int N = readInt();
296         if (N < 0) {
297             return null;
298         }
299         float[] val = new float[N];
300         for (int i = 0; i < val.length; i++) {
301             val[i] = readFloat();
302         }
303         return val;
304     }
305 
306     @Implementation
writeDoubleArray(double[] val)307     public void writeDoubleArray(double[] val) {
308         if (val == null) {
309             writeInt(-1);
310             return;
311         }
312         writeInt(val.length);
313         for (double f : val)
314             writeDouble(f);
315     }
316 
317     @Implementation
readDoubleArray(double[] val)318     public void readDoubleArray(double[] val) {
319         int N = readInt();
320         if (val.length != N)
321             throw new RuntimeException("bad array lengths");
322         for (int i = 0; i < val.length; i++) {
323             val[i] = readDouble();
324         }
325     }
326 
327     @Implementation
createDoubleArray()328     public double[] createDoubleArray() {
329         int N = readInt();
330         if (N < 0) {
331             return null;
332         }
333         double[] val = new double[N];
334         for (int i = 0; i < val.length; i++) {
335             val[i] = readDouble();
336         }
337         return val;
338     }
339 
340     @Implementation
writeIntArray(int[] val)341     public void writeIntArray(int[] val) {
342         if (val == null) {
343             writeInt(-1);
344             return;
345         }
346         writeInt(val.length);
347         for (int f : val)
348             writeInt(f);
349     }
350 
351     @Implementation
readIntArray(int[] val)352     public void readIntArray(int[] val) {
353         int N = readInt();
354         if (val.length != N)
355             throw new RuntimeException("bad array lengths");
356         for (int i = 0; i < val.length; i++) {
357             val[i] = readInt();
358         }
359     }
360 
361     @Implementation
createIntArray()362     public int[] createIntArray() {
363         int N = readInt();
364         if (N < 0) {
365             return null;
366         }
367         int[] val = new int[N];
368         for (int i = 0; i < val.length; i++) {
369             val[i] = readInt();
370         }
371         return val;
372     }
373 
374     @Implementation
writeByteArray(byte[] val)375     public void writeByteArray(byte[] val) {
376         if (val == null) {
377             writeInt(-1);
378             return;
379         }
380         writeInt(val.length);
381         for (byte f : val)
382             writeByte(f);
383     }
384 
385     @Implementation
readByteArray(byte[] val)386     public void readByteArray(byte[] val) {
387         int N = readInt();
388         if (val.length != N)
389             throw new RuntimeException("bad array lengths");
390         for (int i = 0; i < val.length; i++) {
391             val[i] = readByte();
392         }
393     }
394 
395     @Implementation
createByteArray()396     public byte[] createByteArray() {
397         int N = readInt();
398         if (N < 0) {
399             return null;
400         }
401         byte[] val = new byte[N];
402         for (int i = 0; i < val.length; i++) {
403             val[i] = readByte();
404         }
405         return val;
406     }
407 
408     @Implementation
writeLongArray(long[] val)409     public void writeLongArray(long[] val) {
410         if (val == null) {
411             writeInt(-1);
412             return;
413         }
414         writeInt(val.length);
415         for (long f : val)
416             writeLong(f);
417     }
418 
419     @Implementation
readLongArray(long[] val)420     public void readLongArray(long[] val) {
421         int N = readInt();
422         if (val.length != N)
423             throw new RuntimeException("bad array lengths");
424         for (int i = 0; i < val.length; i++) {
425             val[i] = readLong();
426         }
427     }
428 
429     @Implementation
createLongArray()430     public long[] createLongArray() {
431         int N = readInt();
432         if (N < 0) {
433             return null;
434         }
435         long[] val = new long[N];
436         for (int i = 0; i < val.length; i++) {
437             val[i] = readLong();
438         }
439         return val;
440     }
441 
442     @Implementation
writeStringArray(String[] val)443     public void writeStringArray(String[] val) {
444         if (val == null) {
445             writeInt(-1);
446             return;
447         }
448         writeInt(val.length);
449         for (String f : val)
450             writeString(f);
451     }
452 
453     @Implementation
createStringArray()454     public String[] createStringArray() {
455         String[] array = null;
456 
457         int N = readInt();
458         if (N >= 0) {
459             array = new String[N];
460             for (int i = 0; i < N; i++) {
461                 array[i] = readString();
462             }
463         }
464         return array;
465     }
466 
467     @Implementation
readStringArray(String[] dest)468     public void readStringArray(String[] dest) {
469         int N = readInt();
470         if (dest.length != N)
471             throw new RuntimeException("bad array lengths");
472         for (int i = 0; i < dest.length; i++) {
473             dest[i] = readString();
474         }
475     }
476 
477     @Implementation
writeStringList(List<String> strings)478     public void writeStringList(List<String> strings) {
479         if (strings == null) {
480             writeInt(-1);
481             return;
482         }
483         int count = strings.size();
484         int i = 0;
485         writeInt(count);
486         while (i < count) {
487             writeString(strings.get(i));
488             i++;
489         }
490     }
491 
492     @Implementation
readStringList(List<String> list)493     public void readStringList(List<String> list) {
494         int listSizeBeforeChange = list.size();
495         int addCount = readInt();
496         int i = 0;
497         for (; i < listSizeBeforeChange && i < addCount; i++) {
498             list.set(i, readString());
499         }
500         for (; i < addCount; i++) {
501             list.add(readString());
502         }
503         for (; i < listSizeBeforeChange; i++) {
504             list.remove(addCount);
505         }
506     }
507 
508     @Implementation
createStringArrayList()509     public ArrayList<String> createStringArrayList() {
510         int N = readInt();
511         if (N < 0) {
512             return null;
513         }
514 
515         ArrayList<String> l = new ArrayList<String>(N);
516         while (N > 0) {
517             l.add(readString());
518             N--;
519         }
520         return l;
521     }
522 
523     @Implementation
writeCharSequenceArray(CharSequence[] val)524     public void writeCharSequenceArray(CharSequence[] val) {
525         if (val != null) {
526             int N = val.length;
527             writeInt(N);
528             for (int i=0; i<N; i++) {
529                 writeCharSequence(val[i]);
530             }
531         } else {
532             writeInt(-1);
533         }
534     }
535 
536     @Implementation
readCharSequenceArray()537     public CharSequence[] readCharSequenceArray() {
538         CharSequence[] array = null;
539 
540         int length = readInt();
541         if (length >= 0)
542         {
543             array = new CharSequence[length];
544 
545             for (int i = 0 ; i < length ; i++)
546             {
547                 array[i] = readCharSequence();
548             }
549         }
550 
551         return array;
552     }
553 
554     @Implementation
writeList(List val)555     public void writeList(List val) {
556         if (val == null) {
557             writeInt(-1);
558             return;
559         }
560         int N = val.size();
561         int i = 0;
562         writeInt(N);
563         while (i < N) {
564             writeValue(val.get(i));
565             i++;
566         }
567     }
568 
569     @Implementation
readList(List outVal, ClassLoader loader)570     public void readList(List outVal, ClassLoader loader) {
571         int N = readInt();
572         readListInternal(outVal, N, loader);
573     }
574 
575     @Implementation
readArrayList(ClassLoader loader)576     public ArrayList readArrayList(ClassLoader loader) {
577         int N = readInt();
578         if (N < 0) {
579             return null;
580         }
581         ArrayList l = new ArrayList(N);
582         readListInternal(l, N, loader);
583         return l;
584     }
585 
586     @Implementation
writeArray(Object[] values)587     public void writeArray(Object[] values) {
588         if (values == null) {
589             writeInt(-1);
590             return;
591         }
592         int N = values.length;
593         writeInt(N);
594         for (Object value : values) {
595             writeValue(value);
596         }
597     }
598 
599     @Implementation
readArray(ClassLoader loader)600     public Object[] readArray(ClassLoader loader) {
601         int N = readInt();
602         if (N < 0) {
603             return null;
604         }
605         Object[] l = new Object[N];
606         readArrayInternal(l, N, loader);
607         return l;
608     }
609 
610     @Implementation
writeValue(Object v)611     public void writeValue(Object v) {
612         if (v == null) {
613             writeInt(VAL_NULL);
614         } else if (v instanceof String) {
615             writeInt(VAL_STRING);
616             writeString((String) v);
617         } else if (v instanceof Integer) {
618             writeInt(VAL_INTEGER);
619             writeInt((Integer) v);
620         } else if (v instanceof Map) {
621             writeInt(VAL_MAP);
622             writeMap((Map) v);
623         } else if (v instanceof Bundle) {
624             // Must be before Parcelable
625             writeInt(VAL_BUNDLE);
626             writeBundle((Bundle) v);
627         } else if (v instanceof Parcelable) {
628             writeInt(VAL_PARCELABLE);
629             writeParcelable((Parcelable) v, 0);
630         } else if (v instanceof Short) {
631             writeInt(VAL_SHORT);
632             writeInt(((Short) v).intValue());
633         } else if (v instanceof Long) {
634             writeInt(VAL_LONG);
635             writeLong((Long) v);
636         } else if (v instanceof Float) {
637             writeInt(VAL_FLOAT);
638             writeFloat((Float) v);
639         } else if (v instanceof Double) {
640             writeInt(VAL_DOUBLE);
641             writeDouble((Double) v);
642         } else if (v instanceof Boolean) {
643             writeInt(VAL_BOOLEAN);
644             writeInt((Boolean) v ? 1 : 0);
645         } else if (v instanceof CharSequence) {
646             // Must be after String
647             writeInt(VAL_CHARSEQUENCE);
648             writeCharSequence((CharSequence) v);
649         } else if (v instanceof List) {
650             writeInt(VAL_LIST);
651             writeList((List) v);
652         } else if (v instanceof boolean[]) {
653             writeInt(VAL_BOOLEANARRAY);
654             writeBooleanArray((boolean[]) v);
655         } else if (v instanceof byte[]) {
656             writeInt(VAL_BYTEARRAY);
657             writeByteArray((byte[]) v);
658         } else if (v instanceof String[]) {
659             writeInt(VAL_STRINGARRAY);
660             writeStringArray((String[]) v);
661         } else if (v instanceof CharSequence[]) {
662             // Must be after String[] and before Object[]
663             writeInt(VAL_CHARSEQUENCEARRAY);
664             writeCharSequenceArray((CharSequence[]) v);
665         } else if (v instanceof Parcelable[]) {
666             writeInt(VAL_PARCELABLEARRAY);
667             writeParcelableArray((Parcelable[]) v, 0);
668         } else if (v instanceof Object[]) {
669             writeInt(VAL_OBJECTARRAY);
670             writeArray((Object[]) v);
671         } else if (v instanceof int[]) {
672             writeInt(VAL_INTARRAY);
673             writeIntArray((int[]) v);
674         } else if (v instanceof long[]) {
675             writeInt(VAL_LONGARRAY);
676             writeLongArray((long[]) v);
677         } else if (v instanceof Byte) {
678             writeInt(VAL_BYTE);
679             writeByte((Byte) v);
680         } else {
681             throw new RuntimeException(
682                     "Parcel: unable to marshal value with type" + v.getClass().getName());
683         }
684     }
685 
686     @Implementation
readValue(ClassLoader loader)687     public Object readValue(ClassLoader loader) {
688         int type = readInt();
689 
690         switch (type) {
691             case VAL_NULL:
692                 return null;
693 
694             case VAL_STRING:
695                 return readString();
696 
697             case VAL_INTEGER:
698                 return readInt();
699 
700             case VAL_MAP:
701                 return readHashMap(loader);
702 
703             case VAL_PARCELABLE:
704                 return readParcelable(loader);
705 
706             case VAL_SHORT:
707                 return (short) readInt();
708 
709             case VAL_LONG:
710                 return readLong();
711 
712             case VAL_FLOAT:
713                 return readFloat();
714 
715             case VAL_DOUBLE:
716                 return readDouble();
717 
718             case VAL_BOOLEAN:
719                 return readInt() == 1;
720 
721             case VAL_CHARSEQUENCE:
722                 return readCharSequence();
723 
724             case VAL_LIST:
725                 return readArrayList(loader);
726 
727             case VAL_BOOLEANARRAY:
728                 return createBooleanArray();
729 
730             case VAL_BYTEARRAY:
731                 return createByteArray();
732 
733             case VAL_STRINGARRAY:
734                 return createStringArray();
735 
736             case VAL_CHARSEQUENCEARRAY:
737                 return readCharSequenceArray();
738 
739             case VAL_OBJECTARRAY:
740                 return readArray(loader);
741 
742             case VAL_INTARRAY:
743                 return createIntArray();
744 
745             case VAL_LONGARRAY:
746                 return createLongArray();
747 
748             case VAL_BYTE:
749                 return readByte();
750 
751             case VAL_PARCELABLEARRAY:
752                 return readParcelableArray(loader);
753 
754             case VAL_BUNDLE:
755                 return readBundle(loader); // loading will be deferred
756 
757             default:
758                 int off = dataPosition() - 4;
759                 throw new RuntimeException(
760                         "Parcel " + this + ": Unmarshalling unknown type code " + type
761                         + " at offset " + off);
762         }
763     }
764 
765     @Implementation
readBundle()766     public Bundle readBundle() {
767         return readBundle(null);
768     }
769 
770     @Implementation
readBundle(ClassLoader loader)771     public Bundle readBundle(ClassLoader loader) {
772         int offset = dataPosition();
773         int N = readInt();
774         if (N < 0) {
775             return null;
776         }
777         int magic = readInt();
778         if (magic != 0x4C444E42) {
779             throw new RuntimeException("Magic number missing from bundle stream");
780         }
781 
782         Bundle bundle = new Bundle();
783 
784         // Read map
785         HashMap m = new HashMap();
786         readMap(m, null);
787 
788         shadowOf(bundle).map.putAll(m);
789 
790         return bundle;
791     }
792 
793     @Implementation
writeBundle(Bundle val)794     public void writeBundle(Bundle val) {
795         if (val == null) {
796             writeInt(-1);
797             return;
798         }
799 
800         writeInt(-1); // dummy, will hold length
801         int oldPos = dataPosition();
802         writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
803 
804         writeMapInternal(shadowOf(val).map);
805         int newPos = dataPosition();
806 
807         // Backpatch length
808         setDataPosition(oldPos - 4);
809         int N = newPos - oldPos;
810         writeInt(N);
811         setDataPosition(newPos);
812     }
813 
814     @Implementation
writeParcelable(Parcelable p, int flags)815     public void writeParcelable(Parcelable p, int flags) {
816         if (p == null) {
817             writeString(null);
818             return;
819         }
820         String name = p.getClass().getName();
821         writeString(name);
822         p.writeToParcel(realParcel, flags);
823     }
824 
825     @Implementation
readParcelable(ClassLoader loader)826     public <T extends Parcelable> T readParcelable(ClassLoader loader) {
827         String name = readString();
828         if (name == null) {
829             return null;
830         }
831         Parcelable.Creator<T> creator;
832         try {
833             Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader);
834             Field f = c.getField("CREATOR");
835             creator = (Parcelable.Creator) f.get(null);
836         } catch (IllegalAccessException e) {
837             Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e);
838             throw new RuntimeException("IllegalAccessException when unmarshalling: " + name);
839         } catch (ClassNotFoundException e) {
840             Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e);
841             throw new RuntimeException("ClassNotFoundException when unmarshalling: " + name);
842         } catch (ClassCastException e) {
843             throw new RuntimeException("Parcelable protocol requires a "
844                     + "Parcelable.Creator object called " + " CREATOR on class " + name);
845         } catch (NoSuchFieldException e) {
846             throw new RuntimeException("Parcelable protocol requires a "
847                     + "Parcelable.Creator object called " + " CREATOR on class " + name);
848         }
849         if (creator == null) {
850             throw new RuntimeException("Parcelable protocol requires a "
851                     + "Parcelable.Creator object called " + " CREATOR on class " + name);
852         }
853 
854         return creator.createFromParcel(realParcel);
855     }
856 
857     @Implementation
createTypedArrayList(Parcelable.Creator c)858     public ArrayList createTypedArrayList(Parcelable.Creator c) {
859         int N = readInt();
860         if (N < 0) {
861             return null;
862         }
863 
864         ArrayList l = new ArrayList(N);
865 
866         while (N > 0) {
867             if (readInt() != 0) {
868                 l.add(c.createFromParcel(realParcel));
869             } else {
870                 l.add(null);
871             }
872             N--;
873         }
874         return l;
875     }
876 
877     @Implementation
writeTypedList(List val)878     public void writeTypedList(List val) {
879         if (val == null) {
880             writeInt(-1);
881             return;
882         }
883 
884         int N = val.size();
885         int i = 0;
886         writeInt(N);
887         while (i < N) {
888             Object item = val.get(i);
889             if (item != null) {
890                 writeInt(1);
891                 ((Parcelable) item).writeToParcel(realParcel, 0);
892             } else {
893                 writeInt(0);
894             }
895             i++;
896         }
897     }
898 
899     @Implementation
writeParcelableArray(T[] value, int parcelableFlags)900     public <T extends Parcelable> void writeParcelableArray(T[] value,
901             int parcelableFlags) {
902         if (value != null) {
903             int N = value.length;
904             writeInt(N);
905             for (int i=0; i<N; i++) {
906                 writeParcelable(value[i], parcelableFlags);
907             }
908         } else {
909             writeInt(-1);
910         }
911     }
912 
913     @Implementation
readParcelableArray(ClassLoader loader)914     public Parcelable[] readParcelableArray(ClassLoader loader) {
915         int N = readInt();
916         if (N < 0) {
917             return null;
918         }
919         Parcelable[] p = new Parcelable[N];
920         for (int i = 0; i < N; i++) {
921             p[i] = readParcelable(loader);
922         }
923         return p;
924     }
925 
926     @Implementation
writeMap(Map val)927     public void writeMap(Map val) {
928         writeMapInternal(val);
929     }
930 
931     @Implementation
readMap(Map outVal, ClassLoader loader)932     public void readMap(Map outVal, ClassLoader loader) {
933         int N = readInt();
934         readMapInternal(outVal, N, loader);
935     }
936 
937     @Implementation
readHashMap(ClassLoader loader)938     public HashMap readHashMap(ClassLoader loader) {
939         int N = readInt();
940         if (N < 0) {
941             return null;
942         }
943         HashMap m = new HashMap(N);
944         readMapInternal(m, N, loader);
945         return m;
946     }
947 
writeMapInternal(Map<String, Object> val)948     private void writeMapInternal(Map<String, Object> val) {
949         if (val == null) {
950             writeInt(-1);
951             return;
952         }
953 
954         Set<Map.Entry<String, Object>> entries = val.entrySet();
955         writeInt(entries.size());
956         for (Map.Entry<String, Object> e : entries) {
957             writeValue(e.getKey());
958             writeValue(e.getValue());
959         }
960     }
961 
readMapInternal(Map outVal, int N, ClassLoader loader)962     private void readMapInternal(Map outVal, int N, ClassLoader loader) {
963         for (int i = 0; i < N; i++) {
964             Object key = readValue(loader);
965             Object value = readValue(loader);
966             outVal.put(key, value);
967         }
968     }
969 
readListInternal(List outVal, int N, ClassLoader loader)970     private void readListInternal(List outVal, int N, ClassLoader loader) {
971         while (N > 0) {
972             Object value = readValue(loader);
973             outVal.add(value);
974             N--;
975         }
976     }
977 
readArrayInternal(Object[] outVal, int N, ClassLoader loader)978     private void readArrayInternal(Object[] outVal, int N, ClassLoader loader) {
979         for (int i = 0; i < N; i++) {
980             Object value = readValue(loader);
981             outVal[i] = value;
982         }
983     }
984 
addValueToList(Pair<Integer, ?> value)985     private void addValueToList(Pair<Integer, ?> value) {
986         if (index < parcelData.size()) {
987             parcelData.set(index, value);
988         } else {
989             parcelData.add(value);
990         }
991         index++;
992     }
993 
readValueFromList(T defaultValue)994     private <T extends Object> T readValueFromList(T defaultValue) {
995         if (index < parcelData.size()) {
996             return (T) parcelData.get(index++).second;
997         } else {
998             return defaultValue;
999         }
1000     }
1001 
getIndex()1002     public int getIndex() {
1003         return index;
1004     }
1005 
getParcelData()1006     public List getParcelData() {
1007         return parcelData;
1008     }
1009 }
1010