
org.robolectric.shadows.ShadowParcel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of framework Show documentation
Show all versions of framework Show documentation
An alternative Android testing framework.
The newest version!
package org.robolectric.shadows;
import android.os.Parcel;
import android.text.TextUtils;
import android.util.Pair;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.util.ReflectionHelpers;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Objects;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static android.os.Build.VERSION_CODES.KITKAT_WATCH;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static org.robolectric.RuntimeEnvironment.castNativePtr;
@Implements(Parcel.class)
@SuppressWarnings("unchecked")
public class ShadowParcel {
@RealObject private Parcel realObject;
private static final Map NATIVE_PTR_TO_PARCEL = new LinkedHashMap<>();
private static long nextNativePtr = 1; // this needs to start above 0, which is a magic number to Parcel
@Implementation
public void writeByteArray(byte[] b, int offset, int len) {
if (b == null) {
realObject.writeInt(-1);
return;
}
Number nativePtr = ReflectionHelpers.getField(realObject, "mNativePtr");
nativeWriteByteArray(nativePtr.longValue(), b, offset, len);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static int nativeDataSize(int nativePtr) {
return nativeDataSize((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static int nativeDataSize(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataSize();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static int nativeDataAvail(int nativePtr) {
return nativeDataAvail((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static int nativeDataAvail(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataAvailable();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static int nativeDataPosition(int nativePtr) {
return nativeDataPosition((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static int nativeDataPosition(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataPosition();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static int nativeDataCapacity(int nativePtr) {
return nativeDataCapacity((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static int nativeDataCapacity(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).dataCapacity();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeSetDataSize(int nativePtr, int size) {
nativeSetDataSize((long) nativePtr, size);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeSetDataSize(long nativePtr, int size) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataSize(size);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeSetDataPosition(int nativePtr, int pos) {
nativeSetDataPosition((long) nativePtr, pos);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeSetDataPosition(long nativePtr, int pos) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataPosition(pos);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeSetDataCapacity(int nativePtr, int size) {
nativeSetDataCapacity((long) nativePtr, size);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeSetDataCapacity(long nativePtr, int size) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataCapacity(size);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len) {
nativeWriteByteArray((long) nativePtr, b, offset, len);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).writeByteArray(b, offset, len);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteInt(int nativePtr, int val) {
nativeWriteInt((long) nativePtr, val);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteInt(long nativePtr, int val) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).writeInt(val);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteLong(int nativePtr, long val) {
nativeWriteLong((long) nativePtr, val);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteLong(long nativePtr, long val) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).writeLong(val);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteFloat(int nativePtr, float val) {
nativeWriteFloat((long) nativePtr, val);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteFloat(long nativePtr, float val) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).writeFloat(val);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteDouble(int nativePtr, double val) {
nativeWriteDouble((long) nativePtr, val);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteDouble(long nativePtr, double val) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).writeDouble(val);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteString(int nativePtr, String val) {
nativeWriteString((long) nativePtr, val);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteString(long nativePtr, String val) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).writeString(val);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static byte[] nativeCreateByteArray(int nativePtr) {
return nativeCreateByteArray((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static byte[] nativeCreateByteArray(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).readByteArray();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static int nativeReadInt(int nativePtr) {
return nativeReadInt((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static int nativeReadInt(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).readInt();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static long nativeReadLong(int nativePtr) {
return nativeReadLong((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static long nativeReadLong(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).readLong();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static float nativeReadFloat(int nativePtr) {
return nativeReadFloat((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static float nativeReadFloat(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).readFloat();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static double nativeReadDouble(int nativePtr) {
return nativeReadDouble((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static double nativeReadDouble(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).readDouble();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static String nativeReadString(int nativePtr) {
return nativeReadString((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static String nativeReadString(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).readString();
}
@Implementation @HiddenApi
synchronized public static Number nativeCreate() {
long nativePtr = nextNativePtr++;
NATIVE_PTR_TO_PARCEL.put(nativePtr, new ByteBuffer());
return castNativePtr(nativePtr);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeFreeBuffer(int nativePtr) {
nativeFreeBuffer((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeFreeBuffer(long nativePtr) {
NATIVE_PTR_TO_PARCEL.get(nativePtr).clear();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeDestroy(int nativePtr) {
nativeDestroy((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeDestroy(long nativePtr) {
NATIVE_PTR_TO_PARCEL.remove(nativePtr);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static byte[] nativeMarshall(int nativePtr) {
return nativeMarshall((long) nativePtr);
}
@Implementation(minSdk = LOLLIPOP)
public static byte[] nativeMarshall(long nativePtr) {
return NATIVE_PTR_TO_PARCEL.get(nativePtr).toByteArray();
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeUnmarshall(int nativePtr, byte[] data, int offset, int length) {
nativeUnmarshall((long) nativePtr, data, offset, length);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeUnmarshall(long nativePtr, byte[] data, int offset, int length) {
NATIVE_PTR_TO_PARCEL.put(nativePtr, ByteBuffer.fromByteArray(data, offset, length));
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeAppendFrom(int thisNativePtr, int otherNativePtr, int offset, int length) {
nativeAppendFrom((long) thisNativePtr, otherNativePtr, offset, length);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeAppendFrom(long thisNativePtr, long otherNativePtr, int offset, int length) {
ByteBuffer thisByteBuffer = NATIVE_PTR_TO_PARCEL.get(thisNativePtr);
ByteBuffer otherByteBuffer = NATIVE_PTR_TO_PARCEL.get(otherNativePtr);
thisByteBuffer.appendFrom(otherByteBuffer, offset, length);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWriteInterfaceToken(int nativePtr, String interfaceName) {
nativeWriteInterfaceToken((long) nativePtr, interfaceName);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWriteInterfaceToken(long nativePtr, String interfaceName) {
// Write StrictMode.ThreadPolicy bits (assume 0 for test).
nativeWriteInt(nativePtr, 0);
nativeWriteString(nativePtr, interfaceName);
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeEnforceInterface(int nativePtr, String interfaceName) {
nativeEnforceInterface((long) nativePtr, interfaceName);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeEnforceInterface(long nativePtr, String interfaceName) {
// Consume StrictMode.ThreadPolicy bits (don't bother setting in test).
nativeReadInt(nativePtr);
String actualInterfaceName = nativeReadString(nativePtr);
if (!Objects.equals(interfaceName, actualInterfaceName)) {
throw new SecurityException("Binder invocation to an incorrect interface");
}
}
private static class ByteBuffer {
// List of elements where a pair is a piece of data and the sizeof that data
private List> buffer = new ArrayList<>();
private int index;
/**
* Removes all elements from the byte buffer
*/
public void clear() {
index = 0;
buffer.clear();
}
/**
* Reads a byte array from the byte buffer based on the current data position
*/
public byte[] readByteArray() {
int length = readInt();
if (length == -1) {
return null;
}
byte[] array = new byte[length];
for (int i = 0; i < length; i++) {
array[i] = readByte();
}
return array;
}
/**
* Writes a byte to the byte buffer at the current data position
*/
public void writeByte(byte b) {
writeValue(Byte.SIZE / 8, b);
}
/**
* Writes a byte array starting at offset for length bytes to the byte buffer at the current
* data position
*/
public void writeByteArray(byte[] b, int offset, int length) {
writeInt(b.length);
for (int i = offset; i < offset + length && i < b.length; i++) {
writeByte(b[i]);
}
}
/**
* Reads a byte from the byte buffer based on the current data position
*/
public byte readByte() {
return readValue((byte) 0);
}
/**
* Writes an int to the byte buffer at the current data position
*/
public void writeInt(int i) {
writeValue(Integer.SIZE / 8, i);
}
/**
* Reads a int from the byte buffer based on the current data position
*/
public int readInt() {
return readValue(0);
}
/**
* Writes a long to the byte buffer at the current data position
*/
public void writeLong(long l) {
writeValue(Long.SIZE / 8, l);
}
/**
* Reads a long from the byte buffer based on the current data position
*/
public long readLong() {
return readValue(0L);
}
/**
* Writes a float to the byte buffer at the current data position
*/
public void writeFloat(float f) {
writeValue(Float.SIZE / 8, f);
}
/**
* Reads a float from the byte buffer based on the current data position
*/
public float readFloat() {
return readValue(0f);
}
/**
* Writes a double to the byte buffer at the current data position
*/
public void writeDouble(double d) {
writeValue(Double.SIZE / 8, d);
}
/**
* Reads a double from the byte buffer based on the current data position
*/
public double readDouble() {
return readValue(0d);
}
/**
* Writes a String to the byte buffer at the current data position
*/
public void writeString(String s) {
int length = TextUtils.isEmpty(s) ? Integer.SIZE / 8 : s.length();
writeValue(length, s);
}
/**
* Reads a String from the byte buffer based on the current data position
*/
public String readString() {
return readValue(null);
}
/**
* Appends the contents of the other byte buffer to this byte buffer
* starting at offset and ending at length.
*
* @param other ByteBuffer to append to this one
* @param offset number of bytes from beginning of byte buffer to start copy from
* @param length number of bytes to copy
*/
public void appendFrom(ByteBuffer other, int offset, int length) {
int otherIndex = other.toIndex(offset);
int otherEndIndex = other.toIndex(offset + length);
for (int i = otherIndex; i < otherEndIndex && i < other.buffer.size(); i++) {
int elementSize = other.buffer.get(i).first;
Object elementValue = other.buffer.get(i).second;
writeValue(elementSize, elementValue);
}
}
/**
* Creates a Byte buffer from a raw byte array.
*
* @param array byte array to read from
* @param offset starting position in bytes to start reading array at
* @param length number of bytes to read from array
*/
public static ByteBuffer fromByteArray(byte[] array, int offset, int length) {
ByteBuffer byteBuffer = new ByteBuffer();
try {
ByteArrayInputStream bis = new ByteArrayInputStream(array, offset,
length);
ObjectInputStream ois = new ObjectInputStream(bis);
int numElements = ois.readInt();
for (int i = 0; i < numElements; i++) {
int sizeOf = ois.readInt();
Object value = ois.readObject();
byteBuffer.buffer.add(Pair.create(sizeOf, value));
}
return byteBuffer;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Converts a ByteBuffer to a raw byte array. This method should be
* symmetrical with fromByteArray.
*/
public byte[] toByteArray() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
int length = buffer.size();
oos.writeInt(length);
for (Pair element : buffer) {
oos.writeInt(element.first);
oos.writeObject(element.second);
}
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Number of unused bytes in this byte buffer.
*/
public int dataAvailable() {
return dataSize() - dataPosition();
}
/**
* Total buffer size in bytes of byte buffer included unused space.
*/
public int dataCapacity() {
return dataSize();
}
/**
* Current data position of byte buffer in bytes. Reads / writes are from this position.
*/
public int dataPosition() {
return toDataPosition(index);
}
/**
* Current amount of bytes currently written for ByteBuffer.
*/
public int dataSize() {
int totalSize = totalSize();
int dataPosition = dataPosition();
return totalSize > dataPosition ? totalSize : dataPosition;
}
/**
* Sets the current data position.
*
* @param pos
* Desired position in bytes
*/
public void setDataPosition(int pos) {
index = toIndex(pos);
}
public void setDataSize(int size) {
// TODO
}
public void setDataCapacity(int size) {
// TODO
}
private int totalSize() {
int size = 0;
for (Pair element : buffer) {
size += element.first;
}
return size;
}
private T readValue(T defaultValue) {
return (index < buffer.size()) ? (T) buffer.get(index++).second : defaultValue;
}
private void writeValue(int i, Object o) {
Pair value = Pair.create(i, o);
if (index < buffer.size()) {
buffer.set(index, value);
} else {
buffer.add(value);
}
index++;
}
private int toDataPosition(int index) {
int pos = 0;
for (int i = 0; i < index; i++) {
pos += buffer.get(i).first;
}
return pos;
}
private int toIndex(int dataPosition) {
int calculatedPos = 0;
int i = 0;
for (; i < buffer.size() && calculatedPos < dataPosition; i++) {
calculatedPos += buffer.get(i).first;
}
return i;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy