| package com.xtremelabs.robolectric.shadows; |
| |
| import static com.xtremelabs.robolectric.Robolectric.shadowOf; |
| |
| import android.os.Bundle; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.util.Pair; |
| |
| import com.xtremelabs.robolectric.Robolectric; |
| import com.xtremelabs.robolectric.bytecode.ShadowWrangler; |
| import com.xtremelabs.robolectric.internal.Implementation; |
| import com.xtremelabs.robolectric.internal.Implements; |
| import com.xtremelabs.robolectric.internal.RealObject; |
| |
| import java.lang.reflect.Field; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| @Implements(Parcel.class) |
| @SuppressWarnings("unchecked") |
| public class ShadowParcel { |
| |
| private static final int VAL_NULL = -1; |
| private static final int VAL_STRING = 0; |
| private static final int VAL_INTEGER = 1; |
| private static final int VAL_MAP = 2; |
| private static final int VAL_BUNDLE = 3; |
| private static final int VAL_PARCELABLE = 4; |
| private static final int VAL_SHORT = 5; |
| private static final int VAL_LONG = 6; |
| private static final int VAL_FLOAT = 7; |
| private static final int VAL_DOUBLE = 8; |
| private static final int VAL_BOOLEAN = 9; |
| private static final int VAL_CHARSEQUENCE = 10; |
| private static final int VAL_LIST = 11; |
| private static final int VAL_BYTEARRAY = 13; |
| private static final int VAL_STRINGARRAY = 14; |
| private static final int VAL_PARCELABLEARRAY = 16; |
| private static final int VAL_OBJECTARRAY = 17; |
| private static final int VAL_INTARRAY = 18; |
| private static final int VAL_LONGARRAY = 19; |
| private static final int VAL_BYTE = 20; |
| private static final int VAL_BOOLEANARRAY = 23; |
| private static final int VAL_CHARSEQUENCEARRAY = 24; |
| |
| private final ArrayList<Pair<Integer, ?>> parcelData = new ArrayList<Pair<Integer, ?>>(); |
| private int index = 0; |
| |
| @RealObject |
| private Parcel realParcel; |
| |
| @Implementation |
| public static Parcel obtain() { |
| return Robolectric.newInstanceOf(Parcel.class); |
| } |
| |
| @Implementation |
| public int dataAvail() { |
| return dataSize() - dataPosition(); |
| } |
| |
| @Implementation |
| public int dataPosition() { |
| return calculateSizeToIndex(index); |
| } |
| |
| @Implementation |
| public int dataSize() { |
| return calculateSizeToIndex(parcelData.size()); |
| } |
| |
| @Implementation |
| public int dataCapacity() { |
| return dataSize(); |
| } |
| |
| @Implementation |
| public void setDataPosition(int pos) { |
| index = calculateIndexFromSizePosition(pos); |
| } |
| |
| private int calculateSizeToIndex(int index) { |
| int size = 0; |
| for (int i = 0; i < index; i++) { |
| size += parcelData.get(i).first; |
| } |
| return size; |
| } |
| |
| private int calculateIndexFromSizePosition(int pos) { |
| int size = 0; |
| for (int i = 0; i < parcelData.size(); i++) { |
| if (size >= pos) { |
| return i; |
| } |
| size += parcelData.get(i).first; |
| } |
| return parcelData.size(); |
| } |
| |
| @Implementation |
| public void writeString(String str) { |
| if (str == null) { |
| writeInt(-1); |
| } else { |
| writeInt(str.length()); |
| addValueToList(Pair.create(str.length(), str)); |
| } |
| } |
| |
| @Implementation |
| public String readString() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } else { |
| return readValueFromList(null); |
| } |
| } |
| |
| @Implementation |
| public CharSequence readCharSequence() { |
| return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(realParcel); |
| } |
| |
| @Implementation |
| public void writeCharSequence(CharSequence val) { |
| TextUtils.writeToParcel(val, realParcel, 0); |
| } |
| |
| @Implementation |
| public void writeInt(int i) { |
| addValueToList(Pair.create(Integer.SIZE / 8, i)); |
| } |
| |
| @Implementation |
| public int readInt() { |
| return readValueFromList(0); |
| } |
| |
| @Implementation |
| public void writeLong(long i) { |
| addValueToList(Pair.create(Long.SIZE / 8, i)); |
| } |
| |
| @Implementation |
| public long readLong() { |
| return readValueFromList((long) 0); |
| } |
| |
| @Implementation |
| public void writeFloat(float f) { |
| addValueToList(Pair.create(Float.SIZE / 8, f)); |
| } |
| |
| @Implementation |
| public float readFloat() { |
| return readValueFromList((float) 0); |
| } |
| |
| @Implementation |
| public void writeDouble(double f) { |
| addValueToList(Pair.create(Double.SIZE / 8, f)); |
| } |
| |
| @Implementation |
| public double readDouble() { |
| return readValueFromList((double) 0); |
| } |
| |
| public void writeBoolean(boolean b) { |
| addValueToList(Pair.create(1, b)); |
| } |
| |
| public boolean readBoolean() { |
| return readValueFromList(false); |
| } |
| |
| public void writeChar(char c) { |
| addValueToList(Pair.create(Character.SIZE / 8, c)); |
| } |
| |
| public char readChar() { |
| return readValueFromList((char) 0); |
| } |
| |
| @Implementation |
| @SuppressWarnings("unchecked") |
| public void writeByte(byte b) { |
| addValueToList(Pair.create(Byte.SIZE / 8, b)); |
| } |
| |
| @Implementation |
| public byte readByte() { |
| return readValueFromList((byte) 0); |
| } |
| |
| @Implementation |
| public void readBooleanArray(boolean[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readBoolean(); |
| } |
| } |
| |
| @Implementation |
| public void writeBooleanArray(boolean[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (boolean b : val) |
| writeBoolean(b); |
| } |
| |
| @Implementation |
| public boolean[] createBooleanArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| boolean[] val = new boolean[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readBoolean(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void readCharArray(char[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readChar(); |
| } |
| } |
| |
| @Implementation |
| public void writeCharArray(char[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (char b : val) |
| writeChar(b); |
| } |
| |
| @Implementation |
| public char[] createCharArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| char[] val = new char[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readChar(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void readFloatArray(float[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readFloat(); |
| } |
| } |
| |
| @Implementation |
| public void writeFloatArray(float[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (float f : val) |
| writeFloat(f); |
| } |
| |
| @Implementation |
| public float[] createFloatArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| float[] val = new float[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readFloat(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void writeDoubleArray(double[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (double f : val) |
| writeDouble(f); |
| } |
| |
| @Implementation |
| public void readDoubleArray(double[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readDouble(); |
| } |
| } |
| |
| @Implementation |
| public double[] createDoubleArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| double[] val = new double[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readDouble(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void writeIntArray(int[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (int f : val) |
| writeInt(f); |
| } |
| |
| @Implementation |
| public void readIntArray(int[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readInt(); |
| } |
| } |
| |
| @Implementation |
| public int[] createIntArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| int[] val = new int[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readInt(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void writeByteArray(byte[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (byte f : val) |
| writeByte(f); |
| } |
| |
| @Implementation |
| public void readByteArray(byte[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readByte(); |
| } |
| } |
| |
| @Implementation |
| public byte[] createByteArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| byte[] val = new byte[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readByte(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void writeLongArray(long[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (long f : val) |
| writeLong(f); |
| } |
| |
| @Implementation |
| public void readLongArray(long[] val) { |
| int N = readInt(); |
| if (val.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readLong(); |
| } |
| } |
| |
| @Implementation |
| public long[] createLongArray() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| long[] val = new long[N]; |
| for (int i = 0; i < val.length; i++) { |
| val[i] = readLong(); |
| } |
| return val; |
| } |
| |
| @Implementation |
| public void writeStringArray(String[] val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| writeInt(val.length); |
| for (String f : val) |
| writeString(f); |
| } |
| |
| @Implementation |
| public String[] createStringArray() { |
| String[] array = null; |
| |
| int N = readInt(); |
| if (N >= 0) { |
| array = new String[N]; |
| for (int i = 0; i < N; i++) { |
| array[i] = readString(); |
| } |
| } |
| return array; |
| } |
| |
| @Implementation |
| public void readStringArray(String[] dest) { |
| int N = readInt(); |
| if (dest.length != N) |
| throw new RuntimeException("bad array lengths"); |
| for (int i = 0; i < dest.length; i++) { |
| dest[i] = readString(); |
| } |
| } |
| |
| @Implementation |
| public void writeStringList(List<String> strings) { |
| if (strings == null) { |
| writeInt(-1); |
| return; |
| } |
| int count = strings.size(); |
| int i = 0; |
| writeInt(count); |
| while (i < count) { |
| writeString(strings.get(i)); |
| i++; |
| } |
| } |
| |
| @Implementation |
| public void readStringList(List<String> list) { |
| int listSizeBeforeChange = list.size(); |
| int addCount = readInt(); |
| int i = 0; |
| for (; i < listSizeBeforeChange && i < addCount; i++) { |
| list.set(i, readString()); |
| } |
| for (; i < addCount; i++) { |
| list.add(readString()); |
| } |
| for (; i < listSizeBeforeChange; i++) { |
| list.remove(addCount); |
| } |
| } |
| |
| @Implementation |
| public ArrayList<String> createStringArrayList() { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| |
| ArrayList<String> l = new ArrayList<String>(N); |
| while (N > 0) { |
| l.add(readString()); |
| N--; |
| } |
| return l; |
| } |
| |
| @Implementation |
| public void writeCharSequenceArray(CharSequence[] val) { |
| if (val != null) { |
| int N = val.length; |
| writeInt(N); |
| for (int i=0; i<N; i++) { |
| writeCharSequence(val[i]); |
| } |
| } else { |
| writeInt(-1); |
| } |
| } |
| |
| @Implementation |
| public CharSequence[] readCharSequenceArray() { |
| CharSequence[] array = null; |
| |
| int length = readInt(); |
| if (length >= 0) |
| { |
| array = new CharSequence[length]; |
| |
| for (int i = 0 ; i < length ; i++) |
| { |
| array[i] = readCharSequence(); |
| } |
| } |
| |
| return array; |
| } |
| |
| @Implementation |
| public void writeList(List val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| int N = val.size(); |
| int i = 0; |
| writeInt(N); |
| while (i < N) { |
| writeValue(val.get(i)); |
| i++; |
| } |
| } |
| |
| @Implementation |
| public void readList(List outVal, ClassLoader loader) { |
| int N = readInt(); |
| readListInternal(outVal, N, loader); |
| } |
| |
| @Implementation |
| public ArrayList readArrayList(ClassLoader loader) { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| ArrayList l = new ArrayList(N); |
| readListInternal(l, N, loader); |
| return l; |
| } |
| |
| @Implementation |
| public void writeArray(Object[] values) { |
| if (values == null) { |
| writeInt(-1); |
| return; |
| } |
| int N = values.length; |
| writeInt(N); |
| for (Object value : values) { |
| writeValue(value); |
| } |
| } |
| |
| @Implementation |
| public Object[] readArray(ClassLoader loader) { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| Object[] l = new Object[N]; |
| readArrayInternal(l, N, loader); |
| return l; |
| } |
| |
| @Implementation |
| public void writeValue(Object v) { |
| if (v == null) { |
| writeInt(VAL_NULL); |
| } else if (v instanceof String) { |
| writeInt(VAL_STRING); |
| writeString((String) v); |
| } else if (v instanceof Integer) { |
| writeInt(VAL_INTEGER); |
| writeInt((Integer) v); |
| } else if (v instanceof Map) { |
| writeInt(VAL_MAP); |
| writeMap((Map) v); |
| } else if (v instanceof Bundle) { |
| // Must be before Parcelable |
| writeInt(VAL_BUNDLE); |
| writeBundle((Bundle) v); |
| } else if (v instanceof Parcelable) { |
| writeInt(VAL_PARCELABLE); |
| writeParcelable((Parcelable) v, 0); |
| } else if (v instanceof Short) { |
| writeInt(VAL_SHORT); |
| writeInt(((Short) v).intValue()); |
| } else if (v instanceof Long) { |
| writeInt(VAL_LONG); |
| writeLong((Long) v); |
| } else if (v instanceof Float) { |
| writeInt(VAL_FLOAT); |
| writeFloat((Float) v); |
| } else if (v instanceof Double) { |
| writeInt(VAL_DOUBLE); |
| writeDouble((Double) v); |
| } else if (v instanceof Boolean) { |
| writeInt(VAL_BOOLEAN); |
| writeInt((Boolean) v ? 1 : 0); |
| } else if (v instanceof CharSequence) { |
| // Must be after String |
| writeInt(VAL_CHARSEQUENCE); |
| writeCharSequence((CharSequence) v); |
| } else if (v instanceof List) { |
| writeInt(VAL_LIST); |
| writeList((List) v); |
| } else if (v instanceof boolean[]) { |
| writeInt(VAL_BOOLEANARRAY); |
| writeBooleanArray((boolean[]) v); |
| } else if (v instanceof byte[]) { |
| writeInt(VAL_BYTEARRAY); |
| writeByteArray((byte[]) v); |
| } else if (v instanceof String[]) { |
| writeInt(VAL_STRINGARRAY); |
| writeStringArray((String[]) v); |
| } else if (v instanceof CharSequence[]) { |
| // Must be after String[] and before Object[] |
| writeInt(VAL_CHARSEQUENCEARRAY); |
| writeCharSequenceArray((CharSequence[]) v); |
| } else if (v instanceof Parcelable[]) { |
| writeInt(VAL_PARCELABLEARRAY); |
| writeParcelableArray((Parcelable[]) v, 0); |
| } else if (v instanceof Object[]) { |
| writeInt(VAL_OBJECTARRAY); |
| writeArray((Object[]) v); |
| } else if (v instanceof int[]) { |
| writeInt(VAL_INTARRAY); |
| writeIntArray((int[]) v); |
| } else if (v instanceof long[]) { |
| writeInt(VAL_LONGARRAY); |
| writeLongArray((long[]) v); |
| } else if (v instanceof Byte) { |
| writeInt(VAL_BYTE); |
| writeByte((Byte) v); |
| } else { |
| throw new RuntimeException( |
| "Parcel: unable to marshal value with type" + v.getClass().getName()); |
| } |
| } |
| |
| @Implementation |
| public Object readValue(ClassLoader loader) { |
| int type = readInt(); |
| |
| switch (type) { |
| case VAL_NULL: |
| return null; |
| |
| case VAL_STRING: |
| return readString(); |
| |
| case VAL_INTEGER: |
| return readInt(); |
| |
| case VAL_MAP: |
| return readHashMap(loader); |
| |
| case VAL_PARCELABLE: |
| return readParcelable(loader); |
| |
| case VAL_SHORT: |
| return (short) readInt(); |
| |
| case VAL_LONG: |
| return readLong(); |
| |
| case VAL_FLOAT: |
| return readFloat(); |
| |
| case VAL_DOUBLE: |
| return readDouble(); |
| |
| case VAL_BOOLEAN: |
| return readInt() == 1; |
| |
| case VAL_CHARSEQUENCE: |
| return readCharSequence(); |
| |
| case VAL_LIST: |
| return readArrayList(loader); |
| |
| case VAL_BOOLEANARRAY: |
| return createBooleanArray(); |
| |
| case VAL_BYTEARRAY: |
| return createByteArray(); |
| |
| case VAL_STRINGARRAY: |
| return createStringArray(); |
| |
| case VAL_CHARSEQUENCEARRAY: |
| return readCharSequenceArray(); |
| |
| case VAL_OBJECTARRAY: |
| return readArray(loader); |
| |
| case VAL_INTARRAY: |
| return createIntArray(); |
| |
| case VAL_LONGARRAY: |
| return createLongArray(); |
| |
| case VAL_BYTE: |
| return readByte(); |
| |
| case VAL_PARCELABLEARRAY: |
| return readParcelableArray(loader); |
| |
| case VAL_BUNDLE: |
| return readBundle(loader); // loading will be deferred |
| |
| default: |
| int off = dataPosition() - 4; |
| throw new RuntimeException( |
| "Parcel " + this + ": Unmarshalling unknown type code " + type |
| + " at offset " + off); |
| } |
| } |
| |
| @Implementation |
| public Bundle readBundle() { |
| return readBundle(null); |
| } |
| |
| @Implementation |
| public Bundle readBundle(ClassLoader loader) { |
| int offset = dataPosition(); |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| int magic = readInt(); |
| if (magic != 0x4C444E42) { |
| throw new RuntimeException("Magic number missing from bundle stream"); |
| } |
| |
| Bundle bundle = new Bundle(); |
| |
| // Read map |
| HashMap m = new HashMap(); |
| readMap(m, null); |
| |
| shadowOf(bundle).map.putAll(m); |
| |
| return bundle; |
| } |
| |
| @Implementation |
| public void writeBundle(Bundle val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| |
| writeInt(-1); // dummy, will hold length |
| int oldPos = dataPosition(); |
| writeInt(0x4C444E42); // 'B' 'N' 'D' 'L' |
| |
| writeMapInternal(shadowOf(val).map); |
| int newPos = dataPosition(); |
| |
| // Backpatch length |
| setDataPosition(oldPos - 4); |
| int N = newPos - oldPos; |
| writeInt(N); |
| setDataPosition(newPos); |
| } |
| |
| @Implementation |
| public void writeParcelable(Parcelable p, int flags) { |
| if (p == null) { |
| writeString(null); |
| return; |
| } |
| String name = p.getClass().getName(); |
| writeString(name); |
| p.writeToParcel(realParcel, flags); |
| } |
| |
| @Implementation |
| public <T extends Parcelable> T readParcelable(ClassLoader loader) { |
| String name = readString(); |
| if (name == null) { |
| return null; |
| } |
| Parcelable.Creator<T> creator; |
| try { |
| Class c = loader == null ? Class.forName(name) : Class.forName(name, true, loader); |
| Field f = c.getField("CREATOR"); |
| creator = (Parcelable.Creator) f.get(null); |
| } catch (IllegalAccessException e) { |
| Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e); |
| throw new RuntimeException("IllegalAccessException when unmarshalling: " + name); |
| } catch (ClassNotFoundException e) { |
| Log.e("Parcel", "Class not found when unmarshalling: " + name + ", e: " + e); |
| throw new RuntimeException("ClassNotFoundException when unmarshalling: " + name); |
| } catch (ClassCastException e) { |
| throw new RuntimeException("Parcelable protocol requires a " |
| + "Parcelable.Creator object called " + " CREATOR on class " + name); |
| } catch (NoSuchFieldException e) { |
| throw new RuntimeException("Parcelable protocol requires a " |
| + "Parcelable.Creator object called " + " CREATOR on class " + name); |
| } |
| if (creator == null) { |
| throw new RuntimeException("Parcelable protocol requires a " |
| + "Parcelable.Creator object called " + " CREATOR on class " + name); |
| } |
| |
| return creator.createFromParcel(realParcel); |
| } |
| |
| @Implementation |
| public ArrayList createTypedArrayList(Parcelable.Creator c) { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| |
| ArrayList l = new ArrayList(N); |
| |
| while (N > 0) { |
| if (readInt() != 0) { |
| l.add(c.createFromParcel(realParcel)); |
| } else { |
| l.add(null); |
| } |
| N--; |
| } |
| return l; |
| } |
| |
| @Implementation |
| public void writeTypedList(List val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| |
| int N = val.size(); |
| int i = 0; |
| writeInt(N); |
| while (i < N) { |
| Object item = val.get(i); |
| if (item != null) { |
| writeInt(1); |
| ((Parcelable) item).writeToParcel(realParcel, 0); |
| } else { |
| writeInt(0); |
| } |
| i++; |
| } |
| } |
| |
| @Implementation |
| public <T extends Parcelable> void writeParcelableArray(T[] value, |
| int parcelableFlags) { |
| if (value != null) { |
| int N = value.length; |
| writeInt(N); |
| for (int i=0; i<N; i++) { |
| writeParcelable(value[i], parcelableFlags); |
| } |
| } else { |
| writeInt(-1); |
| } |
| } |
| |
| @Implementation |
| public Parcelable[] readParcelableArray(ClassLoader loader) { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| Parcelable[] p = new Parcelable[N]; |
| for (int i = 0; i < N; i++) { |
| p[i] = readParcelable(loader); |
| } |
| return p; |
| } |
| |
| @Implementation |
| public void writeMap(Map val) { |
| writeMapInternal(val); |
| } |
| |
| @Implementation |
| public void readMap(Map outVal, ClassLoader loader) { |
| int N = readInt(); |
| readMapInternal(outVal, N, loader); |
| } |
| |
| @Implementation |
| public HashMap readHashMap(ClassLoader loader) { |
| int N = readInt(); |
| if (N < 0) { |
| return null; |
| } |
| HashMap m = new HashMap(N); |
| readMapInternal(m, N, loader); |
| return m; |
| } |
| |
| private void writeMapInternal(Map<String, Object> val) { |
| if (val == null) { |
| writeInt(-1); |
| return; |
| } |
| |
| Set<Map.Entry<String, Object>> entries = val.entrySet(); |
| writeInt(entries.size()); |
| for (Map.Entry<String, Object> e : entries) { |
| writeValue(e.getKey()); |
| writeValue(e.getValue()); |
| } |
| } |
| |
| private void readMapInternal(Map outVal, int N, ClassLoader loader) { |
| for (int i = 0; i < N; i++) { |
| Object key = readValue(loader); |
| Object value = readValue(loader); |
| outVal.put(key, value); |
| } |
| } |
| |
| private void readListInternal(List outVal, int N, ClassLoader loader) { |
| while (N > 0) { |
| Object value = readValue(loader); |
| outVal.add(value); |
| N--; |
| } |
| } |
| |
| private void readArrayInternal(Object[] outVal, int N, ClassLoader loader) { |
| for (int i = 0; i < N; i++) { |
| Object value = readValue(loader); |
| outVal[i] = value; |
| } |
| } |
| |
| private void addValueToList(Pair<Integer, ?> value) { |
| if (index < parcelData.size()) { |
| parcelData.set(index, value); |
| } else { |
| parcelData.add(value); |
| } |
| index++; |
| } |
| |
| private <T extends Object> T readValueFromList(T defaultValue) { |
| if (index < parcelData.size()) { |
| return (T) parcelData.get(index++).second; |
| } else { |
| return defaultValue; |
| } |
| } |
| |
| public int getIndex() { |
| return index; |
| } |
| |
| public List getParcelData() { |
| return parcelData; |
| } |
| } |