/* * 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.ObjectStreamClass; 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.
* *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.
* *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:
* *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.)
* *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)}. * *
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()}. * *
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 long 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;
private static final int VAL_PERSISTABLEBUNDLE = 25;
// 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(long nativePtr);
private static native int nativeDataAvail(long nativePtr);
private static native int nativeDataPosition(long nativePtr);
private static native int nativeDataCapacity(long nativePtr);
private static native void nativeSetDataSize(long nativePtr, int size);
private static native void nativeSetDataPosition(long nativePtr, int pos);
private static native void nativeSetDataCapacity(long nativePtr, int size);
private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds);
private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
private static native void nativeWriteInt(long nativePtr, int val);
private static native void nativeWriteLong(long nativePtr, long val);
private static native void nativeWriteFloat(long nativePtr, float val);
private static native void nativeWriteDouble(long nativePtr, double val);
private static native void nativeWriteString(long nativePtr, String val);
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(long nativePtr);
private static native int nativeReadInt(long nativePtr);
private static native long nativeReadLong(long nativePtr);
private static native float nativeReadFloat(long nativePtr);
private static native double nativeReadDouble(long nativePtr);
private static native String nativeReadString(long nativePtr);
private static native IBinder nativeReadStrongBinder(long nativePtr);
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
private static native long nativeCreate();
private static native void nativeFreeBuffer(long nativePtr);
private static native void nativeDestroy(long nativePtr);
private static native byte[] nativeMarshall(long nativePtr);
private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offest, int length);
private static native void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
private static native boolean nativeHasFileDescriptors(long nativePtr);
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
public final static Parcelable.Creator 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. 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 {@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). The supported exception types are:
*
*
*
* @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;
}
/**
* Throw an exception with the given message. Not intended for use
* outside the Parcel class.
*
* @param code Used to determine which exception class to throw.
* @param msg The 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 new Bundle object from the parcel at the current
* dataPosition(). Returns null if the previously written Bundle object was
* null.
*/
public final PersistableBundle readPersistableBundle() {
return readPersistableBundle(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 PersistableBundle readPersistableBundle(ClassLoader loader) {
int length = readInt();
if (length < 0) {
if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
return null;
}
final PersistableBundle bundle = new PersistableBundle(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