Merge "Adding typed Parcel read/write APIs." am: d3199a6084
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1832336 Change-Id: I8a2341eef230f078c53b31a03478fa30e3774147
This commit is contained in:
@@ -31444,12 +31444,15 @@ package android.os {
|
|||||||
method public int readInt();
|
method public int readInt();
|
||||||
method public void readIntArray(@NonNull int[]);
|
method public void readIntArray(@NonNull int[]);
|
||||||
method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
|
method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
|
||||||
|
method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>);
|
||||||
method public long readLong();
|
method public long readLong();
|
||||||
method public void readLongArray(@NonNull long[]);
|
method public void readLongArray(@NonNull long[]);
|
||||||
method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
|
method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
|
||||||
method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
|
method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
|
||||||
|
method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
|
||||||
method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
|
method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
|
||||||
method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
|
method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
|
||||||
|
method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>);
|
||||||
method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
|
method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
|
||||||
method @Nullable public android.os.PersistableBundle readPersistableBundle();
|
method @Nullable public android.os.PersistableBundle readPersistableBundle();
|
||||||
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
|
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
|
||||||
|
|||||||
@@ -2807,7 +2807,20 @@ public final class Parcel {
|
|||||||
*/
|
*/
|
||||||
public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
|
public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
|
||||||
int N = readInt();
|
int N = readInt();
|
||||||
readListInternal(outVal, N, loader);
|
readListInternal(outVal, N, loader, /* clazz */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as
|
||||||
|
* the type required for each item. If the item to be deserialized is not an instance
|
||||||
|
* of that class or any of its children class
|
||||||
|
* a {@link BadParcelableException} will be thrown.
|
||||||
|
*/
|
||||||
|
public <T> void readList(@NonNull List<? super T> outVal,
|
||||||
|
@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
|
||||||
|
Objects.requireNonNull(clazz);
|
||||||
|
int n = readInt();
|
||||||
|
readListInternal(outVal, n, loader, clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3006,7 +3019,7 @@ public final class Parcel {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ArrayList l = new ArrayList(N);
|
ArrayList l = new ArrayList(N);
|
||||||
readListInternal(l, N, loader);
|
readListInternal(l, N, loader, /* clazz */ null);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3406,12 +3419,21 @@ public final class Parcel {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public final Object readValue(@Nullable ClassLoader loader) {
|
public final Object readValue(@Nullable ClassLoader loader) {
|
||||||
|
return readValue(loader, /* clazz */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz The type of the object expected or {@code null} for performing no checks.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
|
||||||
int type = readInt();
|
int type = readInt();
|
||||||
final Object object;
|
final T object;
|
||||||
if (isLengthPrefixed(type)) {
|
if (isLengthPrefixed(type)) {
|
||||||
int length = readInt();
|
int length = readInt();
|
||||||
int start = dataPosition();
|
int start = dataPosition();
|
||||||
object = readValue(type, loader);
|
object = readValue(type, loader, clazz);
|
||||||
int actual = dataPosition() - start;
|
int actual = dataPosition() - start;
|
||||||
if (actual != length) {
|
if (actual != length) {
|
||||||
Slog.wtfStack(TAG,
|
Slog.wtfStack(TAG,
|
||||||
@@ -3419,7 +3441,7 @@ public final class Parcel {
|
|||||||
+ " consumed " + actual + " bytes, but " + length + " expected.");
|
+ " consumed " + actual + " bytes, but " + length + " expected.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
object = readValue(type, loader);
|
object = readValue(type, loader, clazz);
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
@@ -3456,7 +3478,7 @@ public final class Parcel {
|
|||||||
setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
|
setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
|
||||||
return new LazyValue(this, start, length, type, loader);
|
return new LazyValue(this, start, length, type, loader);
|
||||||
} else {
|
} else {
|
||||||
return readValue(type, loader);
|
return readValue(type, loader, /* clazz */ null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3588,105 +3610,145 @@ public final class Parcel {
|
|||||||
/**
|
/**
|
||||||
* Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
|
* Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
|
||||||
* type first.
|
* type first.
|
||||||
|
* @param clazz The type of the object expected or {@code null} for performing no checks.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Nullable
|
@Nullable
|
||||||
private Object readValue(int type, @Nullable ClassLoader loader) {
|
private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
|
||||||
|
final Object object;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VAL_NULL:
|
case VAL_NULL:
|
||||||
return null;
|
object = null;
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_STRING:
|
case VAL_STRING:
|
||||||
return readString();
|
object = readString();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_INTEGER:
|
case VAL_INTEGER:
|
||||||
return readInt();
|
object = readInt();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_MAP:
|
case VAL_MAP:
|
||||||
return readHashMap(loader);
|
object = readHashMap(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_PARCELABLE:
|
case VAL_PARCELABLE:
|
||||||
return readParcelable(loader);
|
object = readParcelableInternal(loader, clazz);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_SHORT:
|
case VAL_SHORT:
|
||||||
return (short) readInt();
|
object = (short) readInt();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_LONG:
|
case VAL_LONG:
|
||||||
return readLong();
|
object = readLong();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_FLOAT:
|
case VAL_FLOAT:
|
||||||
return readFloat();
|
object = readFloat();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_DOUBLE:
|
case VAL_DOUBLE:
|
||||||
return readDouble();
|
object = readDouble();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_BOOLEAN:
|
case VAL_BOOLEAN:
|
||||||
return readInt() == 1;
|
object = readInt() == 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_CHARSEQUENCE:
|
case VAL_CHARSEQUENCE:
|
||||||
return readCharSequence();
|
object = readCharSequence();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_LIST:
|
case VAL_LIST:
|
||||||
return readArrayList(loader);
|
object = readArrayList(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_BOOLEANARRAY:
|
case VAL_BOOLEANARRAY:
|
||||||
return createBooleanArray();
|
object = createBooleanArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_BYTEARRAY:
|
case VAL_BYTEARRAY:
|
||||||
return createByteArray();
|
object = createByteArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_STRINGARRAY:
|
case VAL_STRINGARRAY:
|
||||||
return readStringArray();
|
object = readStringArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_CHARSEQUENCEARRAY:
|
case VAL_CHARSEQUENCEARRAY:
|
||||||
return readCharSequenceArray();
|
object = readCharSequenceArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_IBINDER:
|
case VAL_IBINDER:
|
||||||
return readStrongBinder();
|
object = readStrongBinder();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_OBJECTARRAY:
|
case VAL_OBJECTARRAY:
|
||||||
return readArray(loader);
|
object = readArray(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_INTARRAY:
|
case VAL_INTARRAY:
|
||||||
return createIntArray();
|
object = createIntArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_LONGARRAY:
|
case VAL_LONGARRAY:
|
||||||
return createLongArray();
|
object = createLongArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_BYTE:
|
case VAL_BYTE:
|
||||||
return readByte();
|
object = readByte();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_SERIALIZABLE:
|
case VAL_SERIALIZABLE:
|
||||||
return readSerializable(loader);
|
object = readSerializable(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_PARCELABLEARRAY:
|
case VAL_PARCELABLEARRAY:
|
||||||
return readParcelableArray(loader);
|
object = readParcelableArray(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_SPARSEARRAY:
|
case VAL_SPARSEARRAY:
|
||||||
return readSparseArray(loader);
|
object = readSparseArray(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_SPARSEBOOLEANARRAY:
|
case VAL_SPARSEBOOLEANARRAY:
|
||||||
return readSparseBooleanArray();
|
object = readSparseBooleanArray();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_BUNDLE:
|
case VAL_BUNDLE:
|
||||||
return readBundle(loader); // loading will be deferred
|
object = readBundle(loader); // loading will be deferred
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_PERSISTABLEBUNDLE:
|
case VAL_PERSISTABLEBUNDLE:
|
||||||
return readPersistableBundle(loader);
|
object = readPersistableBundle(loader);
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_SIZE:
|
case VAL_SIZE:
|
||||||
return readSize();
|
object = readSize();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_SIZEF:
|
case VAL_SIZEF:
|
||||||
return readSizeF();
|
object = readSizeF();
|
||||||
|
break;
|
||||||
|
|
||||||
case VAL_DOUBLEARRAY:
|
case VAL_DOUBLEARRAY:
|
||||||
return createDoubleArray();
|
object = createDoubleArray();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
int off = dataPosition() - 4;
|
int off = dataPosition() - 4;
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off);
|
"Parcel " + this + ": Unmarshalling unknown type code " + type
|
||||||
|
+ " at offset " + off);
|
||||||
}
|
}
|
||||||
|
if (clazz != null && !clazz.isInstance(object)) {
|
||||||
|
throw new BadParcelableException("Unparcelled object " + object
|
||||||
|
+ " is not an instance of required class " + clazz.getName()
|
||||||
|
+ " provided in the parameter");
|
||||||
|
}
|
||||||
|
return (T) object;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLengthPrefixed(int type) {
|
private boolean isLengthPrefixed(int type) {
|
||||||
@@ -3714,17 +3776,42 @@ public final class Parcel {
|
|||||||
* @throws BadParcelableException Throws BadParcelableException if there
|
* @throws BadParcelableException Throws BadParcelableException if there
|
||||||
* was an error trying to instantiate the Parcelable.
|
* was an error trying to instantiate the Parcelable.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
|
public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
|
||||||
Parcelable.Creator<?> creator = readParcelableCreator(loader);
|
return readParcelableInternal(loader, /* clazz */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type
|
||||||
|
* required for each item. If the item to be deserialized is not an instance of that class or
|
||||||
|
* any of its children classes a {@link BadParcelableException} will be thrown.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader,
|
||||||
|
@NonNull Class<T> clazz) {
|
||||||
|
Objects.requireNonNull(clazz);
|
||||||
|
return readParcelableInternal(loader, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param clazz The type of the parcelable expected or {@code null} for performing no checks.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Nullable
|
||||||
|
private <T> T readParcelableInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
|
||||||
|
if (clazz != null && !Parcelable.class.isAssignableFrom(clazz)) {
|
||||||
|
throw new BadParcelableException("About to unparcel a parcelable object "
|
||||||
|
+ " but class required " + clazz.getName() + " is not Parcelable");
|
||||||
|
}
|
||||||
|
Parcelable.Creator<?> creator = readParcelableCreatorInternal(loader, clazz);
|
||||||
if (creator == null) {
|
if (creator == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
|
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
|
||||||
Parcelable.ClassLoaderCreator<?> classLoaderCreator =
|
Parcelable.ClassLoaderCreator<?> classLoaderCreator =
|
||||||
(Parcelable.ClassLoaderCreator<?>) creator;
|
(Parcelable.ClassLoaderCreator<?>) creator;
|
||||||
return (T) classLoaderCreator.createFromParcel(this, loader);
|
return (T) classLoaderCreator.createFromParcel(this, loader);
|
||||||
}
|
}
|
||||||
return (T) creator.createFromParcel(this);
|
return (T) creator.createFromParcel(this);
|
||||||
}
|
}
|
||||||
@@ -3758,6 +3845,28 @@ public final class Parcel {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
|
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
|
||||||
|
return readParcelableCreatorInternal(loader, /* clazz */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter
|
||||||
|
* as the required type. If the item to be deserialized is not an instance of that class
|
||||||
|
* or any of its children classes a {@link BadParcelableException} will be thrown.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public <T> Parcelable.Creator<T> readParcelableCreator(
|
||||||
|
@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
|
||||||
|
Objects.requireNonNull(clazz);
|
||||||
|
return readParcelableCreatorInternal(loader, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz The type of the parcelable expected or {@code null} for performing no checks.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Nullable
|
||||||
|
private <T> Parcelable.Creator<T> readParcelableCreatorInternal(
|
||||||
|
@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
|
||||||
String name = readString();
|
String name = readString();
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -3773,7 +3882,15 @@ public final class Parcel {
|
|||||||
creator = map.get(name);
|
creator = map.get(name);
|
||||||
}
|
}
|
||||||
if (creator != null) {
|
if (creator != null) {
|
||||||
return creator;
|
if (clazz != null) {
|
||||||
|
Class<?> parcelableClass = creator.getClass().getEnclosingClass();
|
||||||
|
if (!clazz.isAssignableFrom(parcelableClass)) {
|
||||||
|
throw new BadParcelableException("Parcelable creator " + name + " is not "
|
||||||
|
+ "a subclass of required class " + clazz.getName()
|
||||||
|
+ " provided in the parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Parcelable.Creator<T>) creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -3789,6 +3906,14 @@ public final class Parcel {
|
|||||||
throw new BadParcelableException("Parcelable protocol requires subclassing "
|
throw new BadParcelableException("Parcelable protocol requires subclassing "
|
||||||
+ "from Parcelable on class " + name);
|
+ "from Parcelable on class " + name);
|
||||||
}
|
}
|
||||||
|
if (clazz != null) {
|
||||||
|
if (!clazz.isAssignableFrom(parcelableClass)) {
|
||||||
|
throw new BadParcelableException("Parcelable creator " + name + " is not "
|
||||||
|
+ "a subclass of required class " + clazz.getName()
|
||||||
|
+ " provided in the parameter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Field f = parcelableClass.getField("CREATOR");
|
Field f = parcelableClass.getField("CREATOR");
|
||||||
if ((f.getModifiers() & Modifier.STATIC) == 0) {
|
if ((f.getModifiers() & Modifier.STATIC) == 0) {
|
||||||
throw new BadParcelableException("Parcelable protocol requires "
|
throw new BadParcelableException("Parcelable protocol requires "
|
||||||
@@ -3826,7 +3951,7 @@ public final class Parcel {
|
|||||||
map.put(name, creator);
|
map.put(name, creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return creator;
|
return (Parcelable.Creator<T>) creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -4076,13 +4201,21 @@ public final class Parcel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readListInternal(@NonNull List outVal, int N,
|
private void readListInternal(@NonNull List outVal, int n,
|
||||||
@Nullable ClassLoader loader) {
|
@Nullable ClassLoader loader) {
|
||||||
while (N > 0) {
|
readListInternal(outVal, n, loader, null);
|
||||||
Object value = readValue(loader);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param clazz The type of the object expected or {@code null} for performing no checks.
|
||||||
|
*/
|
||||||
|
private <T> void readListInternal(@NonNull List<? super T> outVal, int n,
|
||||||
|
@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
|
||||||
|
while (n > 0) {
|
||||||
|
T value = readValue(loader, clazz);
|
||||||
//Log.d(TAG, "Unmarshalling value=" + value);
|
//Log.d(TAG, "Unmarshalling value=" + value);
|
||||||
outVal.add(value);
|
outVal.add(value);
|
||||||
N--;
|
n--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user