android.os.Parcel Maven / Gradle / Ivy
Show all versions of android-all Show documentation
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Container for a message (data and object references) that can
* be sent through an IBinder. A Parcel can contain both flattened data
* that will be unflattened on the other side of the IPC (using the various
* methods here for writing specific types, or the general
* {@link Parcelable} interface), and references to live {@link IBinder}
* objects that will result in the other side receiving a proxy IBinder
* connected with the original IBinder in the Parcel.
*
* Parcel is not a general-purpose
* serialization mechanism. This class (and the corresponding
* {@link Parcelable} API for placing arbitrary objects into a Parcel) is
* designed as a high-performance IPC transport. As such, it is not
* appropriate to place any Parcel data in to persistent storage: changes
* in the underlying implementation of any of the data in the Parcel can
* render older data unreadable.
*
* The bulk of the Parcel API revolves around reading and writing data
* of various types. There are six major classes of such functions available.
*
* Primitives
*
* The most basic data functions are for writing and reading primitive
* data types: {@link #writeByte}, {@link #readByte}, {@link #writeDouble},
* {@link #readDouble}, {@link #writeFloat}, {@link #readFloat}, {@link #writeInt},
* {@link #readInt}, {@link #writeLong}, {@link #readLong},
* {@link #writeString}, {@link #readString}. Most other
* data operations are built on top of these. The given data is written and
* read using the endianess of the host CPU.
*
* Primitive Arrays
*
* There are a variety of methods for reading and writing raw arrays
* of primitive objects, which generally result in writing a 4-byte length
* followed by the primitive data items. The methods for reading can either
* read the data into an existing array, or create and return a new array.
* These available types are:
*
*
* - {@link #writeBooleanArray(boolean[])},
* {@link #readBooleanArray(boolean[])}, {@link #createBooleanArray()}
*
- {@link #writeByteArray(byte[])},
* {@link #writeByteArray(byte[], int, int)}, {@link #readByteArray(byte[])},
* {@link #createByteArray()}
*
- {@link #writeCharArray(char[])}, {@link #readCharArray(char[])},
* {@link #createCharArray()}
*
- {@link #writeDoubleArray(double[])}, {@link #readDoubleArray(double[])},
* {@link #createDoubleArray()}
*
- {@link #writeFloatArray(float[])}, {@link #readFloatArray(float[])},
* {@link #createFloatArray()}
*
- {@link #writeIntArray(int[])}, {@link #readIntArray(int[])},
* {@link #createIntArray()}
*
- {@link #writeLongArray(long[])}, {@link #readLongArray(long[])},
* {@link #createLongArray()}
*
- {@link #writeStringArray(String[])}, {@link #readStringArray(String[])},
* {@link #createStringArray()}.
*
- {@link #writeSparseBooleanArray(SparseBooleanArray)},
* {@link #readSparseBooleanArray()}.
*
*
* Parcelables
*
* The {@link Parcelable} protocol provides an extremely efficient (but
* low-level) protocol for objects to write and read themselves from Parcels.
* You can use the direct methods {@link #writeParcelable(Parcelable, int)}
* and {@link #readParcelable(ClassLoader)} or
* {@link #writeParcelableArray} and
* {@link #readParcelableArray(ClassLoader)} to write or read. These
* methods write both the class type and its data to the Parcel, allowing
* that class to be reconstructed from the appropriate class loader when
* later reading.
*
* There are also some methods that provide a more efficient way to work
* with Parcelables: {@link #writeTypedArray},
* {@link #writeTypedList(List)},
* {@link #readTypedArray} and {@link #readTypedList}. These methods
* do not write the class information of the original object: instead, the
* caller of the read function must know what type to expect and pass in the
* appropriate {@link Parcelable.Creator Parcelable.Creator} instead to
* properly construct the new object and read its data. (To more efficient
* write and read a single Parceable object, you can directly call
* {@link Parcelable#writeToParcel Parcelable.writeToParcel} and
* {@link Parcelable.Creator#createFromParcel Parcelable.Creator.createFromParcel}
* yourself.)
*
* Bundles
*
* A special type-safe container, called {@link Bundle}, is available
* for key/value maps of heterogeneous values. This has many optimizations
* for improved performance when reading and writing data, and its type-safe
* API avoids difficult to debug type errors when finally marshalling the
* data contents into a Parcel. The methods to use are
* {@link #writeBundle(Bundle)}, {@link #readBundle()}, and
* {@link #readBundle(ClassLoader)}.
*
*
Active Objects
*
* An unusual feature of Parcel is the ability to read and write active
* objects. For these objects the actual contents of the object is not
* written, rather a special token referencing the object is written. When
* reading the object back from the Parcel, you do not get a new instance of
* the object, but rather a handle that operates on the exact same object that
* was originally written. There are two forms of active objects available.
*
* {@link Binder} objects are a core facility of Android's general cross-process
* communication system. The {@link IBinder} interface describes an abstract
* protocol with a Binder object. Any such interface can be written in to
* a Parcel, and upon reading you will receive either the original object
* implementing that interface or a special proxy implementation
* that communicates calls back to the original object. The methods to use are
* {@link #writeStrongBinder(IBinder)},
* {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()},
* {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])},
* {@link #createBinderArray()},
* {@link #writeBinderList(List)}, {@link #readBinderList(List)},
* {@link #createBinderArrayList()}.
*
* FileDescriptor objects, representing raw Linux file descriptor identifiers,
* can be written and {@link ParcelFileDescriptor} objects returned to operate
* on the original file descriptor. The returned file descriptor is a dup
* of the original file descriptor: the object and fd is different, but
* operating on the same underlying file stream, with the same position, etc.
* The methods to use are {@link #writeFileDescriptor(FileDescriptor)},
* {@link #readFileDescriptor()}.
*
*
Untyped Containers
*
* A final class of methods are for writing and reading standard Java
* containers of arbitrary types. These all revolve around the
* {@link #writeValue(Object)} and {@link #readValue(ClassLoader)} methods
* which define the types of objects allowed. The container methods are
* {@link #writeArray(Object[])}, {@link #readArray(ClassLoader)},
* {@link #writeList(List)}, {@link #readList(List, ClassLoader)},
* {@link #readArrayList(ClassLoader)},
* {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)},
* {@link #writeSparseArray(SparseArray)},
* {@link #readSparseArray(ClassLoader)}.
*/
public final class Parcel {
private static final boolean DEBUG_RECYCLE = false;
private static final boolean DEBUG_ARRAY_MAP = false;
private static final String TAG = "Parcel";
@SuppressWarnings({"UnusedDeclaration"})
private int mNativePtr; // used by native code
/**
* Flag indicating if {@link #mNativePtr} was allocated by this object,
* indicating that we're responsible for its lifecycle.
*/
private boolean mOwnsNativeParcelObject;
private RuntimeException mStack;
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
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_SPARSEARRAY = 12;
private static final int VAL_BYTEARRAY = 13;
private static final int VAL_STRINGARRAY = 14;
private static final int VAL_IBINDER = 15;
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_SERIALIZABLE = 21;
private static final int VAL_SPARSEBOOLEANARRAY = 22;
private static final int VAL_BOOLEANARRAY = 23;
private static final int VAL_CHARSEQUENCEARRAY = 24;
// The initial int32 in a Binder call's reply Parcel header:
private static final int EX_SECURITY = -1;
private static final int EX_BAD_PARCELABLE = -2;
private static final int EX_ILLEGAL_ARGUMENT = -3;
private static final int EX_NULL_POINTER = -4;
private static final int EX_ILLEGAL_STATE = -5;
private static final int EX_NETWORK_MAIN_THREAD = -6;
private static final int EX_HAS_REPLY_HEADER = -128; // special; see below
private static native int nativeDataSize(int nativePtr);
private static native int nativeDataAvail(int nativePtr);
private static native int nativeDataPosition(int nativePtr);
private static native int nativeDataCapacity(int nativePtr);
private static native void nativeSetDataSize(int nativePtr, int size);
private static native void nativeSetDataPosition(int nativePtr, int pos);
private static native void nativeSetDataCapacity(int nativePtr, int size);
private static native boolean nativePushAllowFds(int nativePtr, boolean allowFds);
private static native void nativeRestoreAllowFds(int nativePtr, boolean lastValue);
private static native void nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len);
private static native void nativeWriteInt(int nativePtr, int val);
private static native void nativeWriteLong(int nativePtr, long val);
private static native void nativeWriteFloat(int nativePtr, float val);
private static native void nativeWriteDouble(int nativePtr, double val);
private static native void nativeWriteString(int nativePtr, String val);
private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);
private static native void nativeWriteFileDescriptor(int nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(int nativePtr);
private static native int nativeReadInt(int nativePtr);
private static native long nativeReadLong(int nativePtr);
private static native float nativeReadFloat(int nativePtr);
private static native double nativeReadDouble(int nativePtr);
private static native String nativeReadString(int nativePtr);
private static native IBinder nativeReadStrongBinder(int nativePtr);
private static native FileDescriptor nativeReadFileDescriptor(int nativePtr);
private static native int nativeCreate();
private static native void nativeFreeBuffer(int nativePtr);
private static native void nativeDestroy(int nativePtr);
private static native byte[] nativeMarshall(int nativePtr);
private static native void nativeUnmarshall(
int nativePtr, byte[] data, int offest, int length);
private static native void nativeAppendFrom(
int thisNativePtr, int otherNativePtr, int offset, int length);
private static native boolean nativeHasFileDescriptors(int nativePtr);
private static native void nativeWriteInterfaceToken(int nativePtr, String interfaceName);
private static native void nativeEnforceInterface(int nativePtr, String interfaceName);
public final static Parcelable.Creator STRING_CREATOR
= new Parcelable.Creator() {
public String createFromParcel(Parcel source) {
return source.readString();
}
public String[] newArray(int size) {
return new String[size];
}
};
/**
* Retrieve a new Parcel object from the pool.
*/
public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
for (int i=0; i= {@link #dataSize}. The difference between it and dataSize() is the
* amount of room left until the parcel needs to re-allocate its
* data buffer.
*/
public final int dataCapacity() {
return nativeDataCapacity(mNativePtr);
}
/**
* Change the amount of data in the parcel. Can be either smaller or
* larger than the current size. If larger than the current capacity,
* more memory will be allocated.
*
* @param size The new number of bytes in the Parcel.
*/
public final void setDataSize(int size) {
nativeSetDataSize(mNativePtr, size);
}
/**
* Move the current read/write position in the parcel.
* @param pos New offset in the parcel; must be between 0 and
* {@link #dataSize}.
*/
public final void setDataPosition(int pos) {
nativeSetDataPosition(mNativePtr, pos);
}
/**
* Change the capacity (current available space) of the parcel.
*
* @param size The new capacity of the parcel, in bytes. Can not be
* less than {@link #dataSize} -- that is, you can not drop existing data
* with this method.
*/
public final void setDataCapacity(int size) {
nativeSetDataCapacity(mNativePtr, size);
}
/** @hide */
public final boolean pushAllowFds(boolean allowFds) {
return nativePushAllowFds(mNativePtr, allowFds);
}
/** @hide */
public final void restoreAllowFds(boolean lastValue) {
nativeRestoreAllowFds(mNativePtr, lastValue);
}
/**
* Returns the raw bytes of the parcel.
*
* The data you retrieve here must not
* be placed in any kind of persistent storage (on local disk, across
* a network, etc). For that, you should use standard serialization
* or another kind of general serialization mechanism. The Parcel
* marshalled representation is highly optimized for local IPC, and as
* such does not attempt to maintain compatibility with data created
* in different versions of the platform.
*/
public final byte[] marshall() {
return nativeMarshall(mNativePtr);
}
/**
* Set the bytes in data to be the raw bytes of this Parcel.
*/
public final void unmarshall(byte[] data, int offest, int length) {
nativeUnmarshall(mNativePtr, data, offest, length);
}
public final void appendFrom(Parcel parcel, int offset, int length) {
nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
}
/**
* Report whether the parcel contains any marshalled file descriptors.
*/
public final boolean hasFileDescriptors() {
return nativeHasFileDescriptors(mNativePtr);
}
/**
* Store or read an IBinder interface token in the parcel at the current
* {@link #dataPosition}. This is used to validate that the marshalled
* transaction is intended for the target interface.
*/
public final void writeInterfaceToken(String interfaceName) {
nativeWriteInterfaceToken(mNativePtr, interfaceName);
}
public final void enforceInterface(String interfaceName) {
nativeEnforceInterface(mNativePtr, interfaceName);
}
/**
* Write a byte array into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
*/
public final void writeByteArray(byte[] b) {
writeByteArray(b, 0, (b != null) ? b.length : 0);
}
/**
* Write a byte array into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
* @param offset Index of first byte to be written.
* @param len Number of bytes to write.
*/
public final void writeByteArray(byte[] b, int offset, int len) {
if (b == null) {
writeInt(-1);
return;
}
Arrays.checkOffsetAndCount(b.length, offset, len);
nativeWriteByteArray(mNativePtr, b, offset, len);
}
/**
* Write an integer value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeInt(int val) {
nativeWriteInt(mNativePtr, val);
}
/**
* Write a long integer value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeLong(long val) {
nativeWriteLong(mNativePtr, val);
}
/**
* Write a floating point value into the parcel at the current
* dataPosition(), growing dataCapacity() if needed.
*/
public final void writeFloat(float val) {
nativeWriteFloat(mNativePtr, val);
}
/**
* Write a double precision floating point value into the parcel at the
* current dataPosition(), growing dataCapacity() if needed.
*/
public final void writeDouble(double val) {
nativeWriteDouble(mNativePtr, val);
}
/**
* Write a string value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeString(String val) {
nativeWriteString(mNativePtr, val);
}
/**
* Write a CharSequence value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
* @hide
*/
public final void writeCharSequence(CharSequence val) {
TextUtils.writeToParcel(val, this, 0);
}
/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongInterface(IInterface val) {
writeStrongBinder(val == null ? null : val.asBinder());
}
/**
* Write a FileDescriptor into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*
*
The file descriptor will not be closed, which may
* result in file descriptor leaks when objects are returned from Binder
* calls. Use {@link ParcelFileDescriptor#writeToParcel} instead, which
* accepts contextual flags and will close the original file descriptor
* if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.
*/
public final void writeFileDescriptor(FileDescriptor val) {
nativeWriteFileDescriptor(mNativePtr, val);
}
/**
* Write a byte value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeByte(byte val) {
writeInt(val);
}
/**
* Please use {@link #writeBundle} instead. Flattens a Map into the parcel
* at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
* The Map values are written using {@link #writeValue} and must follow
* the specification there.
*
* It is strongly recommended to use {@link #writeBundle} instead of
* this method, since the Bundle class provides a type-safe API that
* allows you to avoid mysterious type errors at the point of marshalling.
*/
public final void writeMap(Map val) {
writeMapInternal((Map) val);
}
/**
* Flatten a Map into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeMapInternal(Map val) {
if (val == null) {
writeInt(-1);
return;
}
Set> entries = val.entrySet();
writeInt(entries.size());
for (Map.Entry e : entries) {
writeValue(e.getKey());
writeValue(e.getValue());
}
}
/**
* Flatten an ArrayMap into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeArrayMapInternal(ArrayMap val) {
if (val == null) {
writeInt(-1);
return;
}
final int N = val.size();
writeInt(N);
if (DEBUG_ARRAY_MAP) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
}
for (int i=0; i val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
writeInt(N);
int i=0;
while (i < N) {
writeInt(val.keyAt(i));
writeValue(val.valueAt(i));
i++;
}
}
public final void writeSparseBooleanArray(SparseBooleanArray val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
writeInt(N);
int i=0;
while (i < N) {
writeInt(val.keyAt(i));
writeByte((byte)(val.valueAt(i) ? 1 : 0));
i++;
}
}
public final void writeBooleanArray(boolean[] val) {
if (val != null) {
int N = val.length;
writeInt(N);
for (int i=0; i>2 as a fast divide-by-4 works in the create*Array() functions
// because dataAvail() will never return a negative number. 4 is
// the size of a stored boolean in the stream.
if (N >= 0 && N <= (dataAvail() >> 2)) {
boolean[] val = new boolean[N];
for (int i=0; i= 0 && N <= (dataAvail() >> 2)) {
char[] val = new char[N];
for (int i=0; i= 0 && N <= (dataAvail() >> 2)) {
int[] val = new int[N];
for (int i=0; i>3 because stored longs are 64 bits
if (N >= 0 && N <= (dataAvail() >> 3)) {
long[] val = new long[N];
for (int i=0; i>2 because stored floats are 4 bytes
if (N >= 0 && N <= (dataAvail() >> 2)) {
float[] val = new float[N];
for (int i=0; i>3 because stored doubles are 8 bytes
if (N >= 0 && N <= (dataAvail() >> 3)) {
double[] val = new double[N];
for (int i=0; i= 0) {
String[] val = new String[N];
for (int i=0; i= 0) {
IBinder[] val = new IBinder[N];
for (int i=0; i void writeTypedList(List val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
int i=0;
writeInt(N);
while (i < N) {
T item = val.get(i);
if (item != null) {
writeInt(1);
item.writeToParcel(this, 0);
} else {
writeInt(0);
}
i++;
}
}
/**
* Flatten a List containing String objects into the parcel, at
* the current dataPosition() and growing dataCapacity() if needed. They
* can later be retrieved with {@link #createStringArrayList} or
* {@link #readStringList}.
*
* @param val The list of strings to be written.
*
* @see #createStringArrayList
* @see #readStringList
*/
public final void writeStringList(List val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
int i=0;
writeInt(N);
while (i < N) {
writeString(val.get(i));
i++;
}
}
/**
* Flatten a List containing IBinder objects into the parcel, at
* the current dataPosition() and growing dataCapacity() if needed. They
* can later be retrieved with {@link #createBinderArrayList} or
* {@link #readBinderList}.
*
* @param val The list of strings to be written.
*
* @see #createBinderArrayList
* @see #readBinderList
*/
public final void writeBinderList(List val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
int i=0;
writeInt(N);
while (i < N) {
writeStrongBinder(val.get(i));
i++;
}
}
/**
* Flatten a heterogeneous array containing a particular object type into
* the parcel, at
* the current dataPosition() and growing dataCapacity() if needed. The
* type of the objects in the array must be one that implements Parcelable.
* Unlike the {@link #writeParcelableArray} method, however, only the
* raw data of the objects is written and not their type, so you must use
* {@link #readTypedArray} with the correct corresponding
* {@link Parcelable.Creator} implementation to unmarshall them.
*
* @param val The array of objects to be written.
* @param parcelableFlags Contextual flags as per
* {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
*
* @see #readTypedArray
* @see #writeParcelableArray
* @see Parcelable.Creator
*/
public final void writeTypedArray(T[] val,
int parcelableFlags) {
if (val != null) {
int N = val.length;
writeInt(N);
for (int i=0; i
* null
* String
* Byte
* Short
* Integer
* Long
* Float
* Double
* Boolean
* String[]
* boolean[]
* byte[]
* int[]
* long[]
* Object[] (supporting objects of the same type defined here).
* {@link Bundle}
* Map (as supported by {@link #writeMap}).
* Any object that implements the {@link Parcelable} protocol.
* Parcelable[]
* CharSequence (as supported by {@link TextUtils#writeToParcel}).
* List (as supported by {@link #writeList}).
* {@link SparseArray} (as supported by {@link #writeSparseArray(SparseArray)}).
* {@link IBinder}
* Any object that implements Serializable (but see
* {@link #writeSerializable} for caveats). Note that all of the
* previous types have relatively efficient implementations for
* writing to a Parcel; having to rely on the generic serialization
* approach is much less efficient and should be avoided whenever
* possible.
*
*
* {@link Parcelable} objects are written with
* {@link Parcelable#writeToParcel} using contextual flags of 0. When
* serializing objects containing {@link ParcelFileDescriptor}s,
* this may result in file descriptor leaks when they are returned from
* Binder calls (where {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}
* should be used).
*/
public final 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 SparseArray) {
writeInt(VAL_SPARSEARRAY);
writeSparseArray((SparseArray) 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 IBinder) {
writeInt(VAL_IBINDER);
writeStrongBinder((IBinder) 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);
writeInt((Byte) v);
} else if (v instanceof Serializable) {
// Must be last
writeInt(VAL_SERIALIZABLE);
writeSerializable((Serializable) v);
} else {
throw new RuntimeException("Parcel: unable to marshal value " + v);
}
}
/**
* Flatten the name of the class of the Parcelable and its contents
* into the parcel.
*
* @param p The Parcelable object to be written.
* @param parcelableFlags Contextual flags as per
* {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
*/
public final void writeParcelable(Parcelable p, int parcelableFlags) {
if (p == null) {
writeString(null);
return;
}
String name = p.getClass().getName();
writeString(name);
p.writeToParcel(this, parcelableFlags);
}
/** @hide */
public final void writeParcelableCreator(Parcelable p) {
String name = p.getClass().getName();
writeString(name);
}
/**
* Write a generic serializable object in to a Parcel. It is strongly
* recommended that this method be avoided, since the serialization
* overhead is extremely large, and this approach will be much slower than
* using the other approaches to writing data in to a Parcel.
*/
public final void writeSerializable(Serializable s) {
if (s == null) {
writeString(null);
return;
}
String name = s.getClass().getName();
writeString(name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(s);
oos.close();
writeByteArray(baos.toByteArray());
} catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " +
"IOException writing serializable object (name = " + name +
")", ioe);
}
}
/**
* Special function for writing an exception result at the header of
* a parcel, to be used when returning an exception from a transaction.
* Note that this currently only supports a few exception types; any other
* exception will be re-thrown by this function as a RuntimeException
* (to be caught by the system's last-resort exception handling when
* dispatching a transaction).
*
* The supported exception types are:
*
* - {@link BadParcelableException}
*
- {@link IllegalArgumentException}
*
- {@link IllegalStateException}
*
- {@link NullPointerException}
*
- {@link SecurityException}
*
- {@link NetworkOnMainThreadException}
*
*
* @param e The Exception to be written.
*
* @see #writeNoException
* @see #readException
*/
public final void writeException(Exception e) {
int code = 0;
if (e instanceof SecurityException) {
code = EX_SECURITY;
} else if (e instanceof BadParcelableException) {
code = EX_BAD_PARCELABLE;
} else if (e instanceof IllegalArgumentException) {
code = EX_ILLEGAL_ARGUMENT;
} else if (e instanceof NullPointerException) {
code = EX_NULL_POINTER;
} else if (e instanceof IllegalStateException) {
code = EX_ILLEGAL_STATE;
} else if (e instanceof NetworkOnMainThreadException) {
code = EX_NETWORK_MAIN_THREAD;
}
writeInt(code);
StrictMode.clearGatheredViolations();
if (code == 0) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new RuntimeException(e);
}
writeString(e.getMessage());
}
/**
* Special function for writing information at the front of the Parcel
* indicating that no exception occurred.
*
* @see #writeException
* @see #readException
*/
public final void writeNoException() {
// Despite the name of this function ("write no exception"),
// it should instead be thought of as "write the RPC response
// header", but because this function name is written out by
// the AIDL compiler, we're not going to rename it.
//
// The response header, in the non-exception case (see also
// writeException above, also called by the AIDL compiler), is
// either a 0 (the default case), or EX_HAS_REPLY_HEADER if
// StrictMode has gathered up violations that have occurred
// during a Binder call, in which case we write out the number
// of violations and their details, serialized, before the
// actual RPC respons data. The receiving end of this is
// readException(), below.
if (StrictMode.hasGatheredViolations()) {
writeInt(EX_HAS_REPLY_HEADER);
final int sizePosition = dataPosition();
writeInt(0); // total size of fat header, to be filled in later
StrictMode.writeGatheredViolationsToParcel(this);
final int payloadPosition = dataPosition();
setDataPosition(sizePosition);
writeInt(payloadPosition - sizePosition); // header size
setDataPosition(payloadPosition);
} else {
writeInt(0);
}
}
/**
* Special function for reading an exception result from the header of
* a parcel, to be used after receiving the result of a transaction. This
* will throw the exception for you if it had been written to the Parcel,
* otherwise return and let you read the normal result data from the Parcel.
*
* @see #writeException
* @see #writeNoException
*/
public final void readException() {
int code = readExceptionCode();
if (code != 0) {
String msg = readString();
readException(code, msg);
}
}
/**
* Parses the header of a Binder call's response Parcel and
* returns the exception code. Deals with lite or fat headers.
* In the common successful case, this header is generally zero.
* In less common cases, it's a small negative number and will be
* followed by an error string.
*
* This exists purely for android.database.DatabaseUtils and
* insulating it from having to handle fat headers as returned by
* e.g. StrictMode-induced RPC responses.
*
* @hide
*/
public final int readExceptionCode() {
int code = readInt();
if (code == EX_HAS_REPLY_HEADER) {
int headerSize = readInt();
if (headerSize == 0) {
Log.e(TAG, "Unexpected zero-sized Parcel reply header.");
} else {
// Currently the only thing in the header is StrictMode stacks,
// but discussions around event/RPC tracing suggest we might
// put that here too. If so, switch on sub-header tags here.
// But for now, just parse out the StrictMode stuff.
StrictMode.readAndHandleBinderCallViolations(this);
}
// And fat response headers are currently only used when
// there are no exceptions, so return no error:
return 0;
}
return code;
}
/**
* Use this function for customized exception handling.
* customized method call this method for all unknown case
* @param code exception code
* @param msg exception message
*/
public final void readException(int code, String msg) {
switch (code) {
case EX_SECURITY:
throw new SecurityException(msg);
case EX_BAD_PARCELABLE:
throw new BadParcelableException(msg);
case EX_ILLEGAL_ARGUMENT:
throw new IllegalArgumentException(msg);
case EX_NULL_POINTER:
throw new NullPointerException(msg);
case EX_ILLEGAL_STATE:
throw new IllegalStateException(msg);
case EX_NETWORK_MAIN_THREAD:
throw new NetworkOnMainThreadException();
}
throw new RuntimeException("Unknown exception code: " + code
+ " msg " + msg);
}
/**
* Read an integer value from the parcel at the current dataPosition().
*/
public final int readInt() {
return nativeReadInt(mNativePtr);
}
/**
* Read a long integer value from the parcel at the current dataPosition().
*/
public final long readLong() {
return nativeReadLong(mNativePtr);
}
/**
* Read a floating point value from the parcel at the current
* dataPosition().
*/
public final float readFloat() {
return nativeReadFloat(mNativePtr);
}
/**
* Read a double precision floating point value from the parcel at the
* current dataPosition().
*/
public final double readDouble() {
return nativeReadDouble(mNativePtr);
}
/**
* Read a string value from the parcel at the current dataPosition().
*/
public final String readString() {
return nativeReadString(mNativePtr);
}
/**
* Read a CharSequence value from the parcel at the current dataPosition().
* @hide
*/
public final CharSequence readCharSequence() {
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this);
}
/**
* Read an object from the parcel at the current dataPosition().
*/
public final IBinder readStrongBinder() {
return nativeReadStrongBinder(mNativePtr);
}
/**
* Read a FileDescriptor from the parcel at the current dataPosition().
*/
public final ParcelFileDescriptor readFileDescriptor() {
FileDescriptor fd = nativeReadFileDescriptor(mNativePtr);
return fd != null ? new ParcelFileDescriptor(fd) : null;
}
/** {@hide} */
public final FileDescriptor readRawFileDescriptor() {
return nativeReadFileDescriptor(mNativePtr);
}
/*package*/ static native FileDescriptor openFileDescriptor(String file,
int mode) throws FileNotFoundException;
/*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig)
throws IOException;
/*package*/ static native void closeFileDescriptor(FileDescriptor desc)
throws IOException;
/*package*/ static native void clearFileDescriptor(FileDescriptor desc);
/**
* Read a byte value from the parcel at the current dataPosition().
*/
public final byte readByte() {
return (byte)(readInt() & 0xff);
}
/**
* Please use {@link #readBundle(ClassLoader)} instead (whose data must have
* been written with {@link #writeBundle}. Read into an existing Map object
* from the parcel at the current dataPosition().
*/
public final void readMap(Map outVal, ClassLoader loader) {
int N = readInt();
readMapInternal(outVal, N, loader);
}
/**
* Read into an existing List object from the parcel at the current
* dataPosition(), using the given class loader to load any enclosed
* Parcelables. If it is null, the default class loader is used.
*/
public final void readList(List outVal, ClassLoader loader) {
int N = readInt();
readListInternal(outVal, N, loader);
}
/**
* Please use {@link #readBundle(ClassLoader)} instead (whose data must have
* been written with {@link #writeBundle}. Read and return a new HashMap
* object from the parcel at the current dataPosition(), using the given
* class loader to load any enclosed Parcelables. Returns null if
* the previously written map object was null.
*/
public final HashMap readHashMap(ClassLoader loader)
{
int N = readInt();
if (N < 0) {
return null;
}
HashMap m = new HashMap(N);
readMapInternal(m, N, loader);
return m;
}
/**
* Read and return a new Bundle object from the parcel at the current
* dataPosition(). Returns null if the previously written Bundle object was
* null.
*/
public final Bundle readBundle() {
return readBundle(null);
}
/**
* Read and return a new Bundle object from the parcel at the current
* dataPosition(), using the given class loader to initialize the class
* loader of the Bundle for later retrieval of Parcelable objects.
* Returns null if the previously written Bundle object was null.
*/
public final Bundle readBundle(ClassLoader loader) {
int length = readInt();
if (length < 0) {
if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
return null;
}
final Bundle bundle = new Bundle(this, length);
if (loader != null) {
bundle.setClassLoader(loader);
}
return bundle;
}
/**
* Read and return a byte[] object from the parcel.
*/
public final byte[] createByteArray() {
return nativeCreateByteArray(mNativePtr);
}
/**
* Read a byte[] object from the parcel and copy it into the
* given byte array.
*/
public final void readByteArray(byte[] val) {
// TODO: make this a native method to avoid the extra copy.
byte[] ba = createByteArray();
if (ba.length == val.length) {
System.arraycopy(ba, 0, val, 0, ba.length);
} else {
throw new RuntimeException("bad array lengths");
}
}
/**
* Read and return a String[] object from the parcel.
* {@hide}
*/
public final String[] readStringArray() {
String[] array = null;
int length = readInt();
if (length >= 0)
{
array = new String[length];
for (int i = 0 ; i < length ; i++)
{
array[i] = readString();
}
}
return array;
}
/**
* Read and return a CharSequence[] object from the parcel.
* {@hide}
*/
public final 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;
}
/**
* Read and return a new ArrayList object from the parcel at the current
* dataPosition(). Returns null if the previously written list object was
* null. The given class loader will be used to load any enclosed
* Parcelables.
*/
public final ArrayList readArrayList(ClassLoader loader) {
int N = readInt();
if (N < 0) {
return null;
}
ArrayList l = new ArrayList(N);
readListInternal(l, N, loader);
return l;
}
/**
* Read and return a new Object array from the parcel at the current
* dataPosition(). Returns null if the previously written array was
* null. The given class loader will be used to load any enclosed
* Parcelables.
*/
public final Object[] readArray(ClassLoader loader) {
int N = readInt();
if (N < 0) {
return null;
}
Object[] l = new Object[N];
readArrayInternal(l, N, loader);
return l;
}
/**
* Read and return a new SparseArray object from the parcel at the current
* dataPosition(). Returns null if the previously written list object was
* null. The given class loader will be used to load any enclosed
* Parcelables.
*/
public final SparseArray readSparseArray(ClassLoader loader) {
int N = readInt();
if (N < 0) {
return null;
}
SparseArray sa = new SparseArray(N);
readSparseArrayInternal(sa, N, loader);
return sa;
}
/**
* Read and return a new SparseBooleanArray object from the parcel at the current
* dataPosition(). Returns null if the previously written list object was
* null.
*/
public final SparseBooleanArray readSparseBooleanArray() {
int N = readInt();
if (N < 0) {
return null;
}
SparseBooleanArray sa = new SparseBooleanArray(N);
readSparseBooleanArrayInternal(sa, N);
return sa;
}
/**
* Read and return a new ArrayList containing a particular object type from
* the parcel that was written with {@link #writeTypedList} at the
* current dataPosition(). Returns null if the
* previously written list object was null. The list must have
* previously been written via {@link #writeTypedList} with the same object
* type.
*
* @return A newly created ArrayList containing objects with the same data
* as those that were previously written.
*
* @see #writeTypedList
*/
public final 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(this));
} else {
l.add(null);
}
N--;
}
return l;
}
/**
* Read into the given List items containing a particular object type
* that were written with {@link #writeTypedList} at the
* current dataPosition(). The list must have
* previously been written via {@link #writeTypedList} with the same object
* type.
*
* @return A newly created ArrayList containing objects with the same data
* as those that were previously written.
*
* @see #writeTypedList
*/
public final void readTypedList(List list, Parcelable.Creator c) {
int M = list.size();
int N = readInt();
int i = 0;
for (; i < M && i < N; i++) {
if (readInt() != 0) {
list.set(i, c.createFromParcel(this));
} else {
list.set(i, null);
}
}
for (; i createStringArrayList() {
int N = readInt();
if (N < 0) {
return null;
}
ArrayList l = new ArrayList(N);
while (N > 0) {
l.add(readString());
N--;
}
return l;
}
/**
* Read and return a new ArrayList containing IBinder objects from
* the parcel that was written with {@link #writeBinderList} at the
* current dataPosition(). Returns null if the
* previously written list object was null.
*
* @return A newly created ArrayList containing strings with the same data
* as those that were previously written.
*
* @see #writeBinderList
*/
public final ArrayList createBinderArrayList() {
int N = readInt();
if (N < 0) {
return null;
}
ArrayList l = new ArrayList(N);
while (N > 0) {
l.add(readStrongBinder());
N--;
}
return l;
}
/**
* Read into the given List items String objects that were written with
* {@link #writeStringList} at the current dataPosition().
*
* @return A newly created ArrayList containing strings with the same data
* as those that were previously written.
*
* @see #writeStringList
*/
public final void readStringList(List list) {
int M = list.size();
int N = readInt();
int i = 0;
for (; i < M && i < N; i++) {
list.set(i, readString());
}
for (; i list) {
int M = list.size();
int N = readInt();
int i = 0;
for (; i < M && i < N; i++) {
list.set(i, readStrongBinder());
}
for (; imust have
* previously been written via {@link #writeTypedArray} with the same
* object type.
*
* @return A newly created array containing objects with the same data
* as those that were previously written.
*
* @see #writeTypedArray
*/
public final T[] createTypedArray(Parcelable.Creator c) {
int N = readInt();
if (N < 0) {
return null;
}
T[] l = c.newArray(N);
for (int i=0; i void readTypedArray(T[] val, Parcelable.Creator c) {
int N = readInt();
if (N == val.length) {
for (int i=0; i T[] readTypedArray(Parcelable.Creator c) {
return createTypedArray(c);
}
/**
* Write a heterogeneous array of Parcelable objects into the Parcel.
* Each object in the array is written along with its class name, so
* that the correct class can later be instantiated. As a result, this
* has significantly more overhead than {@link #writeTypedArray}, but will
* correctly handle an array containing more than one type of object.
*
* @param value The array of objects to be written.
* @param parcelableFlags Contextual flags as per
* {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
*
* @see #writeTypedArray
*/
public final void writeParcelableArray(T[] value,
int parcelableFlags) {
if (value != null) {
int N = value.length;
writeInt(N);
for (int i=0; i T readParcelable(ClassLoader loader) {
Parcelable.Creator creator = readParcelableCreator(loader);
if (creator == null) {
return null;
}
if (creator instanceof Parcelable.ClassLoaderCreator>) {
return ((Parcelable.ClassLoaderCreator)creator).createFromParcel(this, loader);
}
return creator.createFromParcel(this);
}
/** @hide */
public final T readCreator(Parcelable.Creator creator,
ClassLoader loader) {
if (creator instanceof Parcelable.ClassLoaderCreator>) {
return ((Parcelable.ClassLoaderCreator)creator).createFromParcel(this, loader);
}
return creator.createFromParcel(this);
}
/** @hide */
public final Parcelable.Creator readParcelableCreator(
ClassLoader loader) {
String name = readString();
if (name == null) {
return null;
}
Parcelable.Creator creator;
synchronized (mCreators) {
HashMap map = mCreators.get(loader);
if (map == null) {
map = new HashMap();
mCreators.put(loader, map);
}
creator = map.get(name);
if (creator == null) {
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(TAG, "Illegal access when unmarshalling: "
+ name, e);
throw new BadParcelableException(
"IllegalAccessException when unmarshalling: " + name);
}
catch (ClassNotFoundException e) {
Log.e(TAG, "Class not found when unmarshalling: "
+ name, e);
throw new BadParcelableException(
"ClassNotFoundException when unmarshalling: " + name);
}
catch (ClassCastException e) {
throw new BadParcelableException("Parcelable protocol requires a "
+ "Parcelable.Creator object called "
+ " CREATOR on class " + name);
}
catch (NoSuchFieldException e) {
throw new BadParcelableException("Parcelable protocol requires a "
+ "Parcelable.Creator object called "
+ " CREATOR on class " + name);
}
catch (NullPointerException e) {
throw new BadParcelableException("Parcelable protocol requires "
+ "the CREATOR object to be static on class " + name);
}
if (creator == null) {
throw new BadParcelableException("Parcelable protocol requires a "
+ "Parcelable.Creator object called "
+ " CREATOR on class " + name);
}
map.put(name, creator);
}
}
return creator;
}
/**
* Read and return a new Parcelable array from the parcel.
* The given class loader will be used to load any enclosed
* Parcelables.
* @return the Parcelable array, or null if the array is null
*/
public final 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] = (Parcelable) readParcelable(loader);
}
return p;
}
/**
* Read and return a new Serializable object from the parcel.
* @return the Serializable object, or null if the Serializable name
* wasn't found in the parcel.
*/
public final Serializable readSerializable() {
String name = readString();
if (name == null) {
// For some reason we were unable to read the name of the Serializable (either there
// is nothing left in the Parcel to read, or the next value wasn't a String), so
// return null, which indicates that the name wasn't found in the parcel.
return null;
}
byte[] serializedData = createByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);
try {
ObjectInputStream ois = new ObjectInputStream(bais);
return (Serializable) ois.readObject();
} catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " +
"IOException reading a Serializable object (name = " + name +
")", ioe);
} catch (ClassNotFoundException cnfe) {
throw new RuntimeException("Parcelable encountered" +
"ClassNotFoundException reading a Serializable object (name = "
+ name + ")", cnfe);
}
}
// Cache of previously looked up CREATOR.createFromParcel() methods for
// particular classes. Keys are the names of the classes, values are
// Method objects.
private static final HashMap>
mCreators = new HashMap>();
static protected final Parcel obtain(int obj) {
final Parcel[] pool = sHolderPool;
synchronized (pool) {
Parcel p;
for (int i=0; i 0) {
Object key = readValue(loader);
Object value = readValue(loader);
outVal.put(key, value);
N--;
}
}
/* package */ void readArrayMapInternal(ArrayMap outVal, int N,
ClassLoader loader) {
if (DEBUG_ARRAY_MAP) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
}
while (N > 0) {
Object key = readValue(loader);
if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + ": key=0x"
+ (key != null ? key.hashCode() : 0) + " " + key);
Object value = readValue(loader);
outVal.append(key, value);
N--;
}
}
/* package */ void readArrayMapSafelyInternal(ArrayMap outVal, int N,
ClassLoader loader) {
if (DEBUG_ARRAY_MAP) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Log.d(TAG, "Reading safely " + N + " ArrayMap entries", here);
}
while (N > 0) {
Object key = readValue(loader);
if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read safe #" + (N-1) + ": key=0x"
+ (key != null ? key.hashCode() : 0) + " " + key);
Object value = readValue(loader);
outVal.put(key, value);
N--;
}
}
private void readListInternal(List outVal, int N,
ClassLoader loader) {
while (N > 0) {
Object value = readValue(loader);
//Log.d(TAG, "Unmarshalling value=" + value);
outVal.add(value);
N--;
}
}
private void readArrayInternal(Object[] outVal, int N,
ClassLoader loader) {
for (int i = 0; i < N; i++) {
Object value = readValue(loader);
//Log.d(TAG, "Unmarshalling value=" + value);
outVal[i] = value;
}
}
private void readSparseArrayInternal(SparseArray outVal, int N,
ClassLoader loader) {
while (N > 0) {
int key = readInt();
Object value = readValue(loader);
//Log.i(TAG, "Unmarshalling key=" + key + " value=" + value);
outVal.append(key, value);
N--;
}
}
private void readSparseBooleanArrayInternal(SparseBooleanArray outVal, int N) {
while (N > 0) {
int key = readInt();
boolean value = this.readByte() == 1;
//Log.i(TAG, "Unmarshalling key=" + key + " value=" + value);
outVal.append(key, value);
N--;
}
}
}