Merge "camera2: Update native<->managed camera metadata marshalers"
This commit is contained in:
committed by
Android (Google) Code Review
commit
fab0eadef2
@@ -17,6 +17,7 @@
|
||||
package android.hardware.camera2;
|
||||
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
@@ -126,11 +127,13 @@ public abstract class CameraMetadata {
|
||||
return keyList;
|
||||
}
|
||||
|
||||
// TODO: make final or abstract
|
||||
public static class Key<T> {
|
||||
|
||||
private boolean mHasTag;
|
||||
private int mTag;
|
||||
private final Class<T> mType;
|
||||
private final TypeReference<T> mTypeReference;
|
||||
private final String mName;
|
||||
|
||||
/**
|
||||
@@ -144,6 +147,22 @@ public abstract class CameraMetadata {
|
||||
}
|
||||
mName = name;
|
||||
mType = type;
|
||||
mTypeReference = TypeReference.createSpecializedTypeReference(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Key(String name, TypeReference<T> typeReference) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("Key needs a valid name");
|
||||
} else if (typeReference == null) {
|
||||
throw new NullPointerException("TypeReference needs to be non-null");
|
||||
}
|
||||
mName = name;
|
||||
mType = (Class<T>)typeReference.getRawType();
|
||||
mTypeReference = typeReference;
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
@@ -152,11 +171,10 @@ public abstract class CameraMetadata {
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return mName.hashCode();
|
||||
return mName.hashCode() ^ mTypeReference.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
@@ -166,9 +184,8 @@ public abstract class CameraMetadata {
|
||||
return false;
|
||||
}
|
||||
|
||||
Key lhs = (Key) o;
|
||||
|
||||
return mName.equals(lhs.mName) && mType.equals(lhs.mType);
|
||||
Key<?> lhs = (Key<?>)o;
|
||||
return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,11 +209,29 @@ public abstract class CameraMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw class backing the type {@code T} for this key.
|
||||
*
|
||||
* <p>The distinction is only important if {@code T} is a generic, e.g.
|
||||
* {@code Range<Integer>} since the nested type will be erased.</p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final Class<T> getType() {
|
||||
// TODO: remove this; other places should use #getTypeReference() instead
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type reference backing the type {@code T} for this key.
|
||||
*
|
||||
* <p>The distinction is only important if {@code T} is a generic, e.g.
|
||||
* {@code Range<Integer>} since the nested type will be retained.</p>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final TypeReference<T> getTypeReference() {
|
||||
return mTypeReference;
|
||||
}
|
||||
}
|
||||
|
||||
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
package android.hardware.camera2;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package android.hardware.camera2;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
import static android.hardware.camera2.RggbChannelVector.*;
|
||||
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
/**
|
||||
* An immutable class to represent a rectangle {@code (x,y, width, height)} with an
|
||||
@@ -186,10 +186,7 @@ public final class MeteringRectangle {
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other instanceof MeteringRectangle) {
|
||||
return equals(other);
|
||||
}
|
||||
return false;
|
||||
return other instanceof MeteringRectangle && equals((MeteringRectangle)other);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,14 +91,14 @@ public final class Rational {
|
||||
* <p>A reduced form of a Rational is calculated by dividing both the numerator and the
|
||||
* denominator by their greatest common divisor.</p>
|
||||
*
|
||||
* <pre>
|
||||
* <pre>{@code
|
||||
* (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true
|
||||
* (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
|
||||
* (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction
|
||||
* (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN)
|
||||
* (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity
|
||||
* (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param obj a reference to another object
|
||||
*
|
||||
@@ -159,16 +159,15 @@ public final class Rational {
|
||||
return (float) mNumerator / (float) mDenominator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final long INT_MASK = 0xffffffffL;
|
||||
// Bias the hash code for the first (2^16) values for both numerator and denominator
|
||||
int numeratorFlipped = mNumerator << 16 | mNumerator >>> 16;
|
||||
|
||||
long asLong = INT_MASK & mNumerator;
|
||||
asLong <<= 32;
|
||||
|
||||
asLong |= (INT_MASK & mDenominator);
|
||||
|
||||
return ((Long)asLong).hashCode();
|
||||
return mDenominator ^ numeratorFlipped;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ package android.hardware.camera2;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import static com.android.internal.util.Preconditions.*;
|
||||
import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
import android.util.Size;
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ public final class StreamConfiguration {
|
||||
final int format, final int width, final int height, final boolean input) {
|
||||
mFormat = checkArgumentFormatInternal(format);
|
||||
mWidth = checkArgumentPositive(width, "width must be positive");
|
||||
mHeight = checkArgumentPositive(width, "height must be positive");
|
||||
mHeight = checkArgumentPositive(height, "height must be positive");
|
||||
mInput = input;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import static com.android.internal.util.Preconditions.*;
|
||||
import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
import android.util.Size;
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ public final class StreamConfigurationDuration {
|
||||
final int format, final int width, final int height, final long durationNs) {
|
||||
mFormat = checkArgumentFormatInternal(format);
|
||||
mWidth = checkArgumentPositive(width, "width must be positive");
|
||||
mHeight = checkArgumentPositive(width, "height must be positive");
|
||||
mHeight = checkArgumentPositive(height, "height must be positive");
|
||||
mDurationNs = checkArgumentNonnegative(durationNs, "durationNs must be non-negative");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ package android.hardware.camera2;
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
import android.view.Surface;
|
||||
import android.util.Size;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package android.hardware.camera2;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
@@ -23,16 +23,33 @@ import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraMetadata;
|
||||
import android.hardware.camera2.CaptureResult;
|
||||
import android.hardware.camera2.Face;
|
||||
import android.hardware.camera2.Rational;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.marshal.MarshalRegistry;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableString;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Implementation of camera metadata marshal/unmarshal across Binder to
|
||||
@@ -89,7 +106,6 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
|
||||
nativeWriteToParcel(dest);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T get(Key<T> key) {
|
||||
T value = getOverride(key);
|
||||
@@ -169,275 +185,6 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
|
||||
mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
|
||||
}
|
||||
|
||||
private static int getTypeSize(int nativeType) {
|
||||
switch(nativeType) {
|
||||
case TYPE_BYTE:
|
||||
return 1;
|
||||
case TYPE_INT32:
|
||||
case TYPE_FLOAT:
|
||||
return 4;
|
||||
case TYPE_INT64:
|
||||
case TYPE_DOUBLE:
|
||||
case TYPE_RATIONAL:
|
||||
return 8;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown type, can't get size "
|
||||
+ nativeType);
|
||||
}
|
||||
|
||||
private static Class<?> getExpectedType(int nativeType) {
|
||||
switch(nativeType) {
|
||||
case TYPE_BYTE:
|
||||
return Byte.TYPE;
|
||||
case TYPE_INT32:
|
||||
return Integer.TYPE;
|
||||
case TYPE_FLOAT:
|
||||
return Float.TYPE;
|
||||
case TYPE_INT64:
|
||||
return Long.TYPE;
|
||||
case TYPE_DOUBLE:
|
||||
return Double.TYPE;
|
||||
case TYPE_RATIONAL:
|
||||
return Rational.class;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown type, can't map to Java type "
|
||||
+ nativeType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
|
||||
int nativeType, boolean sizeOnly) {
|
||||
|
||||
if (!sizeOnly) {
|
||||
/**
|
||||
* Rewrite types when the native type doesn't match the managed type
|
||||
* - Boolean -> Byte
|
||||
* - Integer -> Byte
|
||||
*/
|
||||
|
||||
if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
|
||||
// Since a boolean can't be cast to byte, and we don't want to use putBoolean
|
||||
boolean asBool = (Boolean) value;
|
||||
byte asByte = (byte) (asBool ? 1 : 0);
|
||||
value = (T) (Byte) asByte;
|
||||
} else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
|
||||
int asInt = (Integer) value;
|
||||
byte asByte = (byte) asInt;
|
||||
value = (T) (Byte) asByte;
|
||||
} else if (type != getExpectedType(nativeType)) {
|
||||
throw new UnsupportedOperationException("Tried to pack a type of " + type +
|
||||
" but we expected the type to be " + getExpectedType(nativeType));
|
||||
}
|
||||
|
||||
if (nativeType == TYPE_BYTE) {
|
||||
buffer.put((Byte) value);
|
||||
} else if (nativeType == TYPE_INT32) {
|
||||
buffer.putInt((Integer) value);
|
||||
} else if (nativeType == TYPE_FLOAT) {
|
||||
buffer.putFloat((Float) value);
|
||||
} else if (nativeType == TYPE_INT64) {
|
||||
buffer.putLong((Long) value);
|
||||
} else if (nativeType == TYPE_DOUBLE) {
|
||||
buffer.putDouble((Double) value);
|
||||
} else if (nativeType == TYPE_RATIONAL) {
|
||||
Rational r = (Rational) value;
|
||||
buffer.putInt(r.getNumerator());
|
||||
buffer.putInt(r.getDenominator());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return getTypeSize(nativeType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
|
||||
boolean sizeOnly) {
|
||||
|
||||
int size = 0;
|
||||
|
||||
if (type.isPrimitive() || type == Rational.class) {
|
||||
size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
|
||||
} else if (type.isEnum()) {
|
||||
size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
|
||||
} else if (type.isArray()) {
|
||||
size = packArray(value, buffer, type, nativeType, sizeOnly);
|
||||
} else {
|
||||
size = packClass(value, buffer, type, nativeType, sizeOnly);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
|
||||
int nativeType, boolean sizeOnly) {
|
||||
|
||||
// TODO: add support for enums with their own values.
|
||||
return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
|
||||
boolean sizeOnly) {
|
||||
|
||||
MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
|
||||
if (marshaler == null) {
|
||||
throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
|
||||
}
|
||||
|
||||
return marshaler.marshal(value, buffer, nativeType, sizeOnly);
|
||||
}
|
||||
|
||||
private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
|
||||
boolean sizeOnly) {
|
||||
|
||||
int size = 0;
|
||||
int arrayLength = Array.getLength(value);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Object> componentType = (Class<Object>)type.getComponentType();
|
||||
|
||||
for (int i = 0; i < arrayLength; ++i) {
|
||||
size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
|
||||
|
||||
T val;
|
||||
|
||||
if (nativeType == TYPE_BYTE) {
|
||||
val = (T) (Byte) buffer.get();
|
||||
} else if (nativeType == TYPE_INT32) {
|
||||
val = (T) (Integer) buffer.getInt();
|
||||
} else if (nativeType == TYPE_FLOAT) {
|
||||
val = (T) (Float) buffer.getFloat();
|
||||
} else if (nativeType == TYPE_INT64) {
|
||||
val = (T) (Long) buffer.getLong();
|
||||
} else if (nativeType == TYPE_DOUBLE) {
|
||||
val = (T) (Double) buffer.getDouble();
|
||||
} else if (nativeType == TYPE_RATIONAL) {
|
||||
val = (T) new Rational(buffer.getInt(), buffer.getInt());
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
|
||||
+ nativeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite types when the native type doesn't match the managed type
|
||||
* - Byte -> Boolean
|
||||
* - Byte -> Integer
|
||||
*/
|
||||
|
||||
if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
|
||||
// Since a boolean can't be cast to byte, and we don't want to use getBoolean
|
||||
byte asByte = (Byte) val;
|
||||
boolean asBool = asByte != 0;
|
||||
val = (T) (Boolean) asBool;
|
||||
} else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
|
||||
byte asByte = (Byte) val;
|
||||
int asInt = asByte;
|
||||
val = (T) (Integer) asInt;
|
||||
} else if (type != getExpectedType(nativeType)) {
|
||||
throw new UnsupportedOperationException("Tried to unpack a type of " + type +
|
||||
" but we expected the type to be " + getExpectedType(nativeType));
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
|
||||
|
||||
if (type.isPrimitive() || type == Rational.class) {
|
||||
return unpackSingleNative(buffer, type, nativeType);
|
||||
}
|
||||
|
||||
if (type.isEnum()) {
|
||||
return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
|
||||
}
|
||||
|
||||
if (type.isArray()) {
|
||||
return unpackArray(buffer, type, nativeType);
|
||||
}
|
||||
|
||||
T instance = unpackClass(buffer, type, nativeType);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
|
||||
int nativeType) {
|
||||
int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
|
||||
return getEnumFromValue(type, ordinal);
|
||||
}
|
||||
|
||||
private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
|
||||
|
||||
MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
|
||||
if (marshaler == null) {
|
||||
throw new IllegalArgumentException("Unknown class type: " + type);
|
||||
}
|
||||
|
||||
return marshaler.unmarshal(buffer, nativeType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
|
||||
|
||||
Class<?> componentType = type.getComponentType();
|
||||
Object array;
|
||||
|
||||
int elementSize = getTypeSize(nativeType);
|
||||
|
||||
MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
|
||||
if (marshaler != null) {
|
||||
elementSize = marshaler.getNativeSize(nativeType);
|
||||
}
|
||||
|
||||
if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
|
||||
int remaining = buffer.remaining();
|
||||
int arraySize = remaining / elementSize;
|
||||
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG,
|
||||
String.format(
|
||||
"Attempting to unpack array (count = %d, element size = %d, bytes " +
|
||||
"remaining = %d) for type %s",
|
||||
arraySize, elementSize, remaining, type));
|
||||
}
|
||||
|
||||
array = Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; ++i) {
|
||||
Object elem = unpackSingle(buffer, componentType, nativeType);
|
||||
Array.set(array, i, elem);
|
||||
}
|
||||
} else {
|
||||
// Dynamic size, use an array list.
|
||||
ArrayList<Object> arrayList = new ArrayList<Object>();
|
||||
|
||||
int primitiveSize = getTypeSize(nativeType);
|
||||
while (buffer.remaining() >= primitiveSize) {
|
||||
Object elem = unpackSingle(buffer, componentType, nativeType);
|
||||
arrayList.add(elem);
|
||||
}
|
||||
|
||||
array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
|
||||
}
|
||||
|
||||
if (buffer.remaining() != 0) {
|
||||
Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
|
||||
+ type);
|
||||
}
|
||||
|
||||
return (T) array;
|
||||
}
|
||||
|
||||
private <T> T getBase(Key<T> key) {
|
||||
int tag = key.getTag();
|
||||
byte[] values = readValues(tag);
|
||||
@@ -445,10 +192,9 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
|
||||
return null;
|
||||
}
|
||||
|
||||
int nativeType = getNativeType(tag);
|
||||
|
||||
Marshaler<T> marshaler = getMarshalerForKey(key);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
|
||||
return unpackSingle(buffer, key.getType(), nativeType);
|
||||
return marshaler.unmarshal(buffer);
|
||||
}
|
||||
|
||||
// Need overwrite some metadata that has different definitions between native
|
||||
@@ -632,19 +378,19 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
|
||||
int tag = key.getTag();
|
||||
|
||||
if (value == null) {
|
||||
writeValues(tag, null);
|
||||
// Erase the entry
|
||||
writeValues(tag, /*src*/null);
|
||||
return;
|
||||
}
|
||||
} // else update the entry to a new value
|
||||
|
||||
int nativeType = getNativeType(tag);
|
||||
|
||||
int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true);
|
||||
Marshaler<T> marshaler = getMarshalerForKey(key);
|
||||
int size = marshaler.calculateMarshalSize(value);
|
||||
|
||||
// TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
|
||||
byte[] values = new byte[size];
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
|
||||
packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false);
|
||||
marshaler.marshal(value, buffer);
|
||||
|
||||
writeValues(tag, values);
|
||||
}
|
||||
@@ -870,125 +616,64 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
|
||||
new HashMap<Class<? extends Enum>, int[]>();
|
||||
/**
|
||||
* Register a non-sequential set of values to be used with the pack/unpack functions.
|
||||
* This enables get/set to correctly marshal the enum into a value that is C-compatible.
|
||||
* Get the marshaler compatible with the {@code key} and type {@code T}.
|
||||
*
|
||||
* @param enumType The class for an enum
|
||||
* @param values A list of values mapping to the ordinals of the enum
|
||||
*
|
||||
* @hide
|
||||
* @throws UnsupportedOperationException
|
||||
* if the native/managed type combination for {@code key} is not supported
|
||||
*/
|
||||
public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
|
||||
if (enumType.getEnumConstants().length != values.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected values array to be the same size as the enumTypes values "
|
||||
+ values.length + " for type " + enumType);
|
||||
}
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "Registered enum values for type " + enumType + " values");
|
||||
}
|
||||
|
||||
sEnumValues.put(enumType, values);
|
||||
private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
|
||||
return MarshalRegistry.getMarshaler(key.getTypeReference(),
|
||||
getNativeType(key.getTag()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the numeric value from an enum. This is usually the same as the ordinal value for
|
||||
* enums that have fully sequential values, although for C-style enums the range of values
|
||||
* may not map 1:1.
|
||||
*
|
||||
* @param enumValue Enum instance
|
||||
* @return Int guaranteed to be ABI-compatible with the C enum equivalent
|
||||
*/
|
||||
private static <T extends Enum<T>> int getEnumValue(T enumValue) {
|
||||
int[] values;
|
||||
values = sEnumValues.get(enumValue.getClass());
|
||||
|
||||
int ordinal = enumValue.ordinal();
|
||||
if (values != null) {
|
||||
return values[ordinal];
|
||||
}
|
||||
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
|
||||
*
|
||||
* @param enumType Class of the enum we want to find
|
||||
* @param value The numeric value of the enum
|
||||
* @return An instance of the enum
|
||||
*/
|
||||
private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
|
||||
int ordinal;
|
||||
|
||||
int[] registeredValues = sEnumValues.get(enumType);
|
||||
if (registeredValues != null) {
|
||||
ordinal = -1;
|
||||
|
||||
for (int i = 0; i < registeredValues.length; ++i) {
|
||||
if (registeredValues[i] == value) {
|
||||
ordinal = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ordinal = value;
|
||||
}
|
||||
|
||||
T[] values = enumType.getEnumConstants();
|
||||
|
||||
if (ordinal < 0 || ordinal >= values.length) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Argument 'value' (%d) was not a valid enum value for type %s "
|
||||
+ "(registered? %b)",
|
||||
value,
|
||||
enumType, (registeredValues != null)));
|
||||
}
|
||||
|
||||
return values[ordinal];
|
||||
}
|
||||
|
||||
static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
|
||||
HashMap<Class<?>, MetadataMarshalClass<?>>();
|
||||
|
||||
private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
|
||||
sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
|
||||
MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
|
||||
|
||||
if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
|
||||
throw new UnsupportedOperationException("Unsupported type " + nativeType +
|
||||
" to be marshalled to/from a " + type);
|
||||
}
|
||||
|
||||
return marshaler;
|
||||
}
|
||||
|
||||
/**
|
||||
* We use a class initializer to allow the native code to cache some field offsets
|
||||
*/
|
||||
static {
|
||||
nativeClassInit();
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static void registerAllMarshalers() {
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "Shall register metadata marshalers");
|
||||
}
|
||||
|
||||
// load built-in marshallers
|
||||
registerMarshaler(new MetadataMarshalRect());
|
||||
registerMarshaler(new MetadataMarshalSize());
|
||||
registerMarshaler(new MetadataMarshalString());
|
||||
MarshalQueryable[] queryList = new MarshalQueryable[] {
|
||||
// marshalers for standard types
|
||||
new MarshalQueryablePrimitive(),
|
||||
new MarshalQueryableEnum(),
|
||||
new MarshalQueryableArray(),
|
||||
|
||||
// pseudo standard types, that expand/narrow the native type into a managed type
|
||||
new MarshalQueryableBoolean(),
|
||||
new MarshalQueryableNativeByteToInteger(),
|
||||
|
||||
// marshalers for custom types
|
||||
new MarshalQueryableRect(),
|
||||
new MarshalQueryableSize(),
|
||||
new MarshalQueryableSizeF(),
|
||||
new MarshalQueryableString(),
|
||||
new MarshalQueryableReprocessFormatsMap(),
|
||||
new MarshalQueryableRange(),
|
||||
new MarshalQueryableMeteringRectangle(),
|
||||
new MarshalQueryableColorSpaceTransform(),
|
||||
new MarshalQueryableStreamConfiguration(),
|
||||
new MarshalQueryableStreamConfigurationDuration(),
|
||||
new MarshalQueryableRggbChannelVector(),
|
||||
|
||||
// generic parcelable marshaler (MUST BE LAST since it has lowest priority)
|
||||
new MarshalQueryableParcelable(),
|
||||
};
|
||||
|
||||
for (MarshalQueryable query : queryList) {
|
||||
MarshalRegistry.registerMarshalQueryable(query);
|
||||
}
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "Registered metadata marshalers");
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
/*
|
||||
* We use a class initializer to allow the native code to cache some field offsets
|
||||
*/
|
||||
nativeClassInit();
|
||||
registerAllMarshalers();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.hardware.camera2.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface MetadataMarshalClass<T> {
|
||||
|
||||
/**
|
||||
* Marshal the specified object instance (value) into a byte buffer.
|
||||
*
|
||||
* @param value the value of type T that we wish to write into the byte buffer
|
||||
* @param buffer the byte buffer into which the marshalled object will be written
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
|
||||
* Guaranteed to be one for which isNativeTypeSupported returns true.
|
||||
* @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
|
||||
* @return the size that needs to be written to the byte buffer
|
||||
*/
|
||||
int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly);
|
||||
|
||||
/**
|
||||
* Unmarshal a new object instance from the byte buffer.
|
||||
* @param buffer the byte buffer, from which we will read the object
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
|
||||
* Guaranteed to be one for which isNativeTypeSupported returns true.
|
||||
* @return a new instance of type T read from the byte buffer
|
||||
*/
|
||||
T unmarshal(ByteBuffer buffer, int nativeType);
|
||||
|
||||
Class<T> getMarshalingClass();
|
||||
|
||||
/**
|
||||
* Determines whether or not this marshaller supports this native type. Most marshallers
|
||||
* will are likely to only support one type.
|
||||
*
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
|
||||
* @return true if it supports, false otherwise
|
||||
*/
|
||||
boolean isNativeTypeSupported(int nativeType);
|
||||
|
||||
public static int NATIVE_SIZE_DYNAMIC = -1;
|
||||
|
||||
/**
|
||||
* How many bytes T will take up if marshalled to/from nativeType
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
|
||||
* @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
|
||||
*/
|
||||
int getNativeSize(int nativeType);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.hardware.camera2.impl;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class MetadataMarshalRect implements MetadataMarshalClass<Rect> {
|
||||
private static final int SIZE = 16;
|
||||
|
||||
@Override
|
||||
public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
|
||||
if (sizeOnly) {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
buffer.putInt(value.left);
|
||||
buffer.putInt(value.top);
|
||||
buffer.putInt(value.width());
|
||||
buffer.putInt(value.height());
|
||||
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rect unmarshal(ByteBuffer buffer, int nativeType) {
|
||||
|
||||
int left = buffer.getInt();
|
||||
int top = buffer.getInt();
|
||||
int width = buffer.getInt();
|
||||
int height = buffer.getInt();
|
||||
|
||||
int right = left + width;
|
||||
int bottom = top + height;
|
||||
|
||||
return new Rect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Rect> getMarshalingClass() {
|
||||
return Rect.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeTypeSupported(int nativeType) {
|
||||
return nativeType == CameraMetadataNative.TYPE_INT32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize(int nativeType) {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.hardware.camera2.impl;
|
||||
|
||||
import android.hardware.camera2.Size;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class MetadataMarshalSize implements MetadataMarshalClass<Size> {
|
||||
|
||||
private static final int SIZE = 8;
|
||||
|
||||
@Override
|
||||
public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
|
||||
if (sizeOnly) {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
buffer.putInt(value.getWidth());
|
||||
buffer.putInt(value.getHeight());
|
||||
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size unmarshal(ByteBuffer buffer, int nativeType) {
|
||||
int width = buffer.getInt();
|
||||
int height = buffer.getInt();
|
||||
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Size> getMarshalingClass() {
|
||||
return Size.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeTypeSupported(int nativeType) {
|
||||
return nativeType == CameraMetadataNative.TYPE_INT32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize(int nativeType) {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.hardware.camera2.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class MetadataMarshalString implements MetadataMarshalClass<String> {
|
||||
|
||||
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
@Override
|
||||
public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
|
||||
byte[] arr = value.getBytes(UTF8_CHARSET);
|
||||
|
||||
if (!sizeOnly) {
|
||||
buffer.put(arr);
|
||||
buffer.put((byte)0); // metadata strings are NULL-terminated
|
||||
}
|
||||
|
||||
return arr.length + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String unmarshal(ByteBuffer buffer, int nativeType) {
|
||||
|
||||
buffer.mark(); // save the current position
|
||||
|
||||
boolean foundNull = false;
|
||||
int stringLength = 0;
|
||||
while (buffer.hasRemaining()) {
|
||||
if (buffer.get() == (byte)0) {
|
||||
foundNull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
stringLength++;
|
||||
}
|
||||
if (!foundNull) {
|
||||
throw new IllegalArgumentException("Strings must be null-terminated");
|
||||
}
|
||||
|
||||
buffer.reset(); // go back to the previously marked position
|
||||
|
||||
byte[] strBytes = new byte[stringLength + 1];
|
||||
buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
|
||||
|
||||
// not including null character
|
||||
return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getMarshalingClass() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeTypeSupported(int nativeType) {
|
||||
return nativeType == CameraMetadataNative.TYPE_BYTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize(int nativeType) {
|
||||
return NATIVE_SIZE_DYNAMIC;
|
||||
}
|
||||
}
|
||||
243
core/java/android/hardware/camera2/marshal/MarshalHelpers.java
Normal file
243
core/java/android/hardware/camera2/marshal/MarshalHelpers.java
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.hardware.camera2.Rational;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
|
||||
/**
|
||||
* Static functions in order to help implementing various marshaler functionality.
|
||||
*
|
||||
* <p>The intention is to statically import everything from this file into another file when
|
||||
* implementing a new marshaler (or marshal queryable).</p>
|
||||
*
|
||||
* <p>The helpers are centered around providing primitive knowledge of the native types,
|
||||
* such as the native size, the managed class wrappers, and various precondition checks.</p>
|
||||
*/
|
||||
public final class MarshalHelpers {
|
||||
|
||||
public static final int SIZEOF_BYTE = 1;
|
||||
public static final int SIZEOF_INT32 = Integer.SIZE / Byte.SIZE;
|
||||
public static final int SIZEOF_INT64 = Long.SIZE / Byte.SIZE;
|
||||
public static final int SIZEOF_FLOAT = Float.SIZE / Byte.SIZE;
|
||||
public static final int SIZEOF_DOUBLE = Double.SIZE / Byte.SIZE;
|
||||
public static final int SIZEOF_RATIONAL = SIZEOF_INT32 * 2;
|
||||
|
||||
/**
|
||||
* Get the size in bytes for the native camera metadata type.
|
||||
*
|
||||
* <p>This used to determine how many bytes it would take to encode/decode a single value
|
||||
* of that {@link nativeType}.</p>
|
||||
*
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
|
||||
* @return size in bytes >= 1
|
||||
*
|
||||
* @throws UnsupportedOperationException if nativeType was not one of the built-in types
|
||||
*/
|
||||
public static int getPrimitiveTypeSize(int nativeType) {
|
||||
switch (nativeType) {
|
||||
case TYPE_BYTE:
|
||||
return SIZEOF_BYTE;
|
||||
case TYPE_INT32:
|
||||
return SIZEOF_INT32;
|
||||
case TYPE_FLOAT:
|
||||
return SIZEOF_FLOAT;
|
||||
case TYPE_INT64:
|
||||
return SIZEOF_INT64;
|
||||
case TYPE_DOUBLE:
|
||||
return SIZEOF_DOUBLE;
|
||||
case TYPE_RATIONAL:
|
||||
return SIZEOF_RATIONAL;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown type, can't get size for "
|
||||
+ nativeType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure that the {@code klass} is one of the metadata-primitive classes.
|
||||
*
|
||||
* @param klass a non-{@code null} reference
|
||||
* @return {@code klass} instance
|
||||
*
|
||||
* @throws UnsupportedOperationException if klass was not one of the built-in classes
|
||||
* @throws NullPointerException if klass was null
|
||||
*
|
||||
* @see #isPrimitiveClass
|
||||
*/
|
||||
public static <T> Class<T> checkPrimitiveClass(Class<T> klass) {
|
||||
checkNotNull(klass, "klass must not be null");
|
||||
|
||||
if (isPrimitiveClass(klass)) {
|
||||
return klass;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported class '" + klass +
|
||||
"'; expected a metadata primitive class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not {@code klass} is one of the metadata-primitive classes.
|
||||
*
|
||||
* <p>The following types (whether boxed or unboxed) are considered primitive:
|
||||
* <ul>
|
||||
* <li>byte
|
||||
* <li>int
|
||||
* <li>float
|
||||
* <li>double
|
||||
* <li>Rational
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* <p>This doesn't strictly follow the java understanding of primitive since
|
||||
* boxed objects are included, Rational is included, and other types such as char and
|
||||
* short are not included.</p>
|
||||
*
|
||||
* @param klass a {@link Class} instance; using {@code null} will return {@code false}
|
||||
* @return {@code true} if primitive, {@code false} otherwise
|
||||
*/
|
||||
public static <T> boolean isPrimitiveClass(Class<T> klass) {
|
||||
if (klass == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (klass == byte.class || klass == Byte.class) {
|
||||
return true;
|
||||
} else if (klass == int.class || klass == Integer.class) {
|
||||
return true;
|
||||
} else if (klass == float.class || klass == Float.class) {
|
||||
return true;
|
||||
} else if (klass == long.class || klass == Long.class) {
|
||||
return true;
|
||||
} else if (klass == double.class || klass == Double.class) {
|
||||
return true;
|
||||
} else if (klass == Rational.class) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap {@code klass} with its wrapper variant if it was a {@code Class} corresponding
|
||||
* to a Java primitive.
|
||||
*
|
||||
* <p>Non-primitive classes are passed through as-is.</p>
|
||||
*
|
||||
* <p>For example, for a primitive {@code int.class => Integer.class},
|
||||
* but for a non-primitive {@code Rational.class => Rational.class}.</p>
|
||||
*
|
||||
* @param klass a {@code Class} reference
|
||||
*
|
||||
* @return wrapped class object, or same class object if non-primitive
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Class<T> wrapClassIfPrimitive(Class<T> klass) {
|
||||
if (klass == byte.class) {
|
||||
return (Class<T>)Byte.class;
|
||||
} else if (klass == int.class) {
|
||||
return (Class<T>)Integer.class;
|
||||
} else if (klass == float.class) {
|
||||
return (Class<T>)Float.class;
|
||||
} else if (klass == long.class) {
|
||||
return (Class<T>)Long.class;
|
||||
} else if (klass == double.class) {
|
||||
return (Class<T>)Double.class;
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-readable representation of the {@code nativeType}, e.g. "TYPE_INT32"
|
||||
*
|
||||
* <p>Out-of-range values return a string with "UNKNOWN" as the prefix.</p>
|
||||
*
|
||||
* @param nativeType the native type
|
||||
*
|
||||
* @return human readable type name
|
||||
*/
|
||||
public static String toStringNativeType(int nativeType) {
|
||||
switch (nativeType) {
|
||||
case TYPE_BYTE:
|
||||
return "TYPE_BYTE";
|
||||
case TYPE_INT32:
|
||||
return "TYPE_INT32";
|
||||
case TYPE_FLOAT:
|
||||
return "TYPE_FLOAT";
|
||||
case TYPE_INT64:
|
||||
return "TYPE_INT64";
|
||||
case TYPE_DOUBLE:
|
||||
return "TYPE_DOUBLE";
|
||||
case TYPE_RATIONAL:
|
||||
return "TYPE_RATIONAL";
|
||||
}
|
||||
|
||||
return "UNKNOWN(" + nativeType + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the {@code nativeType} is one of the native types supported
|
||||
* by {@link CameraMetadataNative}.
|
||||
*
|
||||
* @param nativeType the native type
|
||||
*
|
||||
* @return the native type
|
||||
*
|
||||
* @throws UnsupportedOperationException if the native type was invalid
|
||||
*/
|
||||
public static int checkNativeType(int nativeType) {
|
||||
switch (nativeType) {
|
||||
case TYPE_BYTE:
|
||||
case TYPE_INT32:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_INT64:
|
||||
case TYPE_DOUBLE:
|
||||
case TYPE_RATIONAL:
|
||||
return nativeType;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the expected and actual native types are equal.
|
||||
*
|
||||
* @param expectedNativeType the expected native type
|
||||
* @param actualNativeType the actual native type
|
||||
* @return the actual native type
|
||||
*
|
||||
* @throws UnsupportedOperationException if the types are not equal
|
||||
*/
|
||||
public static int checkNativeTypeEquals(int expectedNativeType, int actualNativeType) {
|
||||
if (expectedNativeType != actualNativeType) {
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("Expected native type %d, but got %d",
|
||||
expectedNativeType, actualNativeType));
|
||||
}
|
||||
|
||||
return actualNativeType;
|
||||
}
|
||||
|
||||
private MarshalHelpers() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal;
|
||||
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
/**
|
||||
* Query if a marshaler can marshal to/from a particular native and managed type; if it supports
|
||||
* the combination, allow creating a marshaler instance to do the serialization.
|
||||
*
|
||||
* <p>Not all queryable instances will support exactly one combination. Some, such as the
|
||||
* primitive queryable will support all primitive to/from managed mappings (as long as they are
|
||||
* 1:1). Others, such as the rectangle queryable will only support integer to rectangle mappings.
|
||||
* </p>
|
||||
*
|
||||
* <p>Yet some others are codependent on other queryables; e.g. array queryables might only support
|
||||
* a type map for {@code T[]} if another queryable exists with support for the component type
|
||||
* {@code T}.</p>
|
||||
*/
|
||||
public interface MarshalQueryable<T> {
|
||||
/**
|
||||
* Create a marshaler between the selected managed and native type.
|
||||
*
|
||||
* <p>This marshaler instance is only good for that specific type mapping; and will refuse
|
||||
* to map other managed types, other native types, or an other combination that isn't
|
||||
* this exact one.</p>
|
||||
*
|
||||
* @param managedType a managed type reference
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
|
||||
* @return
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if {@link #isTypeMappingSupported} returns {@code false}
|
||||
*/
|
||||
public Marshaler<T> createMarshaler(
|
||||
TypeReference<T> managedType, int nativeType);
|
||||
|
||||
/**
|
||||
* Determine whether or not this query marshal is able to create a marshaler that will
|
||||
* support the managed type and native type mapping.
|
||||
*
|
||||
* <p>If this returns {@code true}, then a marshaler can be instantiated by
|
||||
* {@link #createMarshaler} that will marshal data to/from the native type
|
||||
* from/to the managed type.</p>
|
||||
*
|
||||
* <p>Most marshalers are likely to only support one type map.</p>
|
||||
*/
|
||||
public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType);
|
||||
}
|
||||
133
core/java/android/hardware/camera2/marshal/MarshalRegistry.java
Normal file
133
core/java/android/hardware/camera2/marshal/MarshalRegistry.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal;
|
||||
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Registry of supported marshalers; add new query-able marshalers or lookup existing ones.</p>
|
||||
*/
|
||||
public class MarshalRegistry {
|
||||
|
||||
/**
|
||||
* Register a marshal queryable for the managed type {@code T}.
|
||||
*
|
||||
* <p>Multiple marshal queryables for the same managed type {@code T} may be registered;
|
||||
* this is desirable if they support different native types (e.g. marshaler 1 supports
|
||||
* {@code Integer <-> TYPE_INT32}, marshaler 2 supports {@code Integer <-> TYPE_BYTE}.</p>
|
||||
*
|
||||
* @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
|
||||
*/
|
||||
public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
|
||||
sRegisteredMarshalQueryables.add(queryable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a marshaler between {@code T} and {@code nativeType}.
|
||||
*
|
||||
* <p>Marshalers are looked up in the order they were registered; earlier registered
|
||||
* marshal queriers get priority.</p>
|
||||
*
|
||||
* @param typeToken The compile-time type reference for {@code T}
|
||||
* @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
|
||||
* @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
|
||||
*
|
||||
* @throws UnsupportedOperationException If no marshaler matching the args could be found
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
|
||||
// TODO: can avoid making a new token each time by code-genning
|
||||
// the list of type tokens and native types from the keys (at the call sites)
|
||||
MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
|
||||
|
||||
/*
|
||||
* Marshalers are instantiated lazily once they are looked up; successive lookups
|
||||
* will not instantiate new marshalers.
|
||||
*/
|
||||
Marshaler<T> marshaler =
|
||||
(Marshaler<T>) sMarshalerMap.get(marshalToken);
|
||||
|
||||
if (sRegisteredMarshalQueryables.size() == 0) {
|
||||
throw new AssertionError("No available query marshalers registered");
|
||||
}
|
||||
|
||||
if (marshaler == null) {
|
||||
// Query each marshaler to see if they support the native/managed type combination
|
||||
for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
|
||||
|
||||
MarshalQueryable<T> castedPotential =
|
||||
(MarshalQueryable<T>)potentialMarshaler;
|
||||
|
||||
if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
|
||||
marshaler = castedPotential.createMarshaler(typeToken, nativeType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (marshaler == null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Could not find marshaler that matches the requested " +
|
||||
"combination of type reference " +
|
||||
typeToken + " and native type " +
|
||||
MarshalHelpers.toStringNativeType(nativeType));
|
||||
}
|
||||
|
||||
sMarshalerMap.put(marshalToken, marshaler);
|
||||
|
||||
return marshaler;
|
||||
}
|
||||
|
||||
private static class MarshalToken<T> {
|
||||
public MarshalToken(TypeReference<T> typeReference, int nativeType) {
|
||||
this.typeReference = typeReference;
|
||||
this.nativeType = nativeType;
|
||||
}
|
||||
|
||||
final TypeReference<T> typeReference;
|
||||
final int nativeType;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof MarshalToken<?>) {
|
||||
MarshalToken<?> otherToken = (MarshalToken<?>)other;
|
||||
return typeReference.equals(otherToken.typeReference) &&
|
||||
nativeType == otherToken.nativeType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return typeReference.hashCode() ^ nativeType;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
|
||||
new ArrayList<MarshalQueryable<?>>();
|
||||
private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
|
||||
new HashMap<MarshalToken<?>, Marshaler<?>>();
|
||||
|
||||
private MarshalRegistry() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
148
core/java/android/hardware/camera2/marshal/Marshaler.java
Normal file
148
core/java/android/hardware/camera2/marshal/Marshaler.java
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal;
|
||||
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Base class to marshal data to/from managed/native metadata byte buffers.
|
||||
*
|
||||
* <p>This class should not be created directly; an instance of it can be obtained
|
||||
* using {@link MarshalQueryable#createMarshaler} for the same type {@code T} if the native type
|
||||
* mapping for {@code T} {@link MarshalQueryable#isTypeMappingSupported supported}.</p>
|
||||
*
|
||||
* @param <T> the compile-time managed type
|
||||
*/
|
||||
public abstract class Marshaler<T> {
|
||||
|
||||
protected final TypeReference<T> mTypeReference;
|
||||
protected final int mNativeType;
|
||||
|
||||
/**
|
||||
* Instantiate a marshaler between a single managed/native type combination.
|
||||
*
|
||||
* <p>This particular managed/native type combination must be supported by
|
||||
* {@link #isTypeMappingSupported}.</p>
|
||||
*
|
||||
* @param query an instance of {@link MarshalQueryable}
|
||||
* @param typeReference the managed type reference
|
||||
* Must be one for which {@link #isTypeMappingSupported} returns {@code true}
|
||||
* @param nativeType the native type, e.g.
|
||||
* {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
|
||||
* Must be one for which {@link #isTypeMappingSupported} returns {@code true}.
|
||||
*
|
||||
* @throws NullPointerException if any args were {@code null}
|
||||
* @throws UnsupportedOperationException if the type mapping was not supported
|
||||
*/
|
||||
protected Marshaler(
|
||||
MarshalQueryable<T> query, TypeReference<T> typeReference, int nativeType) {
|
||||
mTypeReference = checkNotNull(typeReference, "typeReference must not be null");
|
||||
mNativeType = checkNativeType(nativeType);
|
||||
|
||||
if (!query.isTypeMappingSupported(typeReference, nativeType)) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Unsupported type marshaling for managed type "
|
||||
+ typeReference + " and native type "
|
||||
+ MarshalHelpers.toStringNativeType(nativeType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal the specified object instance (value) into a byte buffer.
|
||||
*
|
||||
* <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
|
||||
* the {@link #calculateMarshalSize marshal size} of {@code value}.</p>
|
||||
*
|
||||
* @param value the value of type T that we wish to write into the byte buffer
|
||||
* @param buffer the byte buffer into which the marshaled object will be written
|
||||
*/
|
||||
public abstract void marshal(T value, ByteBuffer buffer);
|
||||
|
||||
/**
|
||||
* Get the size in bytes for how much space would be required to write this {@code value}
|
||||
* into a byte buffer using the given {@code nativeType}.
|
||||
*
|
||||
* <p>If the size of this {@code T} instance when serialized into a buffer is always constant,
|
||||
* then this method will always return the same value (and particularly, it will return
|
||||
* an equivalent value to {@link #getNativeSize()}.</p>
|
||||
*
|
||||
* <p>Overriding this method is a must when the size is {@link NATIVE_SIZE_DYNAMIC dynamic}.</p>
|
||||
*
|
||||
* @param value the value of type T that we wish to write into the byte buffer
|
||||
* @return the size that would need to be written to the byte buffer
|
||||
*/
|
||||
public int calculateMarshalSize(T value) {
|
||||
int nativeSize = getNativeSize();
|
||||
|
||||
if (nativeSize == NATIVE_SIZE_DYNAMIC) {
|
||||
throw new AssertionError("Override this function for dynamically-sized objects");
|
||||
}
|
||||
|
||||
return nativeSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshal a new object instance from the byte buffer into its managed type.
|
||||
*
|
||||
* <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
|
||||
* the {@link #calculateMarshalSize marshal size} of the returned {@code T} instance.</p>
|
||||
*
|
||||
* @param buffer the byte buffer, from which we will read the object
|
||||
* @return a new instance of type T read from the byte buffer
|
||||
*/
|
||||
public abstract T unmarshal(ByteBuffer buffer);
|
||||
|
||||
/**
|
||||
* Used to denote variable-length data structures.
|
||||
*
|
||||
* <p>If the size is dynamic then we can't know ahead of time how big of a data structure
|
||||
* to preallocate for e.g. arrays, so one object must be unmarshaled at a time.</p>
|
||||
*/
|
||||
public static int NATIVE_SIZE_DYNAMIC = -1;
|
||||
|
||||
/**
|
||||
* How many bytes a single instance of {@code T} will take up if marshalled to/from
|
||||
* {@code nativeType}.
|
||||
*
|
||||
* <p>When unmarshaling data from native to managed, the instance {@code T} is not yet
|
||||
* available. If the native size is always a fixed mapping regardless of the instance of
|
||||
* {@code T} (e.g. if the type is not a container of some sort), it can be used to preallocate
|
||||
* containers for {@code T} to avoid resizing them.</p>
|
||||
*
|
||||
* <p>In particular, the array marshaler takes advantage of this (when size is not dynamic)
|
||||
* to preallocate arrays of the right length when unmarshaling an array {@code T[]}.</p>
|
||||
*
|
||||
* @return a size in bytes, or {@link #NATIVE_SIZE_DYNAMIC} if the size is dynamic
|
||||
*/
|
||||
public abstract int getNativeSize();
|
||||
|
||||
/**
|
||||
* The type reference for {@code T} for the managed type side of this marshaler.
|
||||
*/
|
||||
public TypeReference<T> getTypeReference() {
|
||||
return mTypeReference;
|
||||
}
|
||||
|
||||
/** The native type corresponding to this marshaler for the native side of this marshaler.*/
|
||||
public int getNativeType() {
|
||||
return mNativeType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.marshal.MarshalRegistry;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal any array {@code T}.
|
||||
*
|
||||
* <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type
|
||||
* also has to exist.</p>
|
||||
*
|
||||
* <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a
|
||||
* built-in primitive (e.g. int[], float[], etc).</p>
|
||||
|
||||
* @param <T> the type of the array (e.g. T = int[], or T = Rational[])
|
||||
*/
|
||||
public class MarshalQueryableArray<T> implements MarshalQueryable<T> {
|
||||
|
||||
private static final String TAG = MarshalQueryableArray.class.getSimpleName();
|
||||
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private class MarshalerArray extends Marshaler<T> {
|
||||
private final Class<T> mClass;
|
||||
private final Marshaler<?> mComponentMarshaler;
|
||||
private final Class<?> mComponentClass;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected MarshalerArray(TypeReference<T> typeReference, int nativeType) {
|
||||
super(MarshalQueryableArray.this, typeReference, nativeType);
|
||||
|
||||
mClass = (Class<T>)typeReference.getRawType();
|
||||
|
||||
TypeReference<?> componentToken = typeReference.getComponentType();
|
||||
mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType);
|
||||
mComponentClass = componentToken.getRawType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(T value, ByteBuffer buffer) {
|
||||
int length = Array.getLength(value);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
marshalArrayElement(mComponentMarshaler, buffer, value, i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T unmarshal(ByteBuffer buffer) {
|
||||
Object array;
|
||||
|
||||
int elementSize = mComponentMarshaler.getNativeSize();
|
||||
|
||||
if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
|
||||
int remaining = buffer.remaining();
|
||||
int arraySize = remaining / elementSize;
|
||||
|
||||
if (remaining % elementSize != 0) {
|
||||
throw new UnsupportedOperationException("Arrays for " + mTypeReference
|
||||
+ " must be packed tighly into a multiple of " + elementSize
|
||||
+ "; but there are " + (remaining % elementSize) + " left over bytes");
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, String.format(
|
||||
"Attempting to unpack array (count = %d, element size = %d, bytes "
|
||||
+ "remaining = %d) for type %s",
|
||||
arraySize, elementSize, remaining, mClass));
|
||||
}
|
||||
|
||||
array = Array.newInstance(mComponentClass, arraySize);
|
||||
for (int i = 0; i < arraySize; ++i) {
|
||||
Object elem = mComponentMarshaler.unmarshal(buffer);
|
||||
Array.set(array, i, elem);
|
||||
}
|
||||
} else {
|
||||
// Dynamic size, use an array list.
|
||||
ArrayList<Object> arrayList = new ArrayList<Object>();
|
||||
|
||||
// Assumes array is packed tightly; no unused bytes allowed
|
||||
while (buffer.hasRemaining()) {
|
||||
Object elem = mComponentMarshaler.unmarshal(buffer);
|
||||
arrayList.add(elem);
|
||||
}
|
||||
|
||||
int arraySize = arrayList.size();
|
||||
array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize));
|
||||
}
|
||||
|
||||
if (buffer.remaining() != 0) {
|
||||
Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
|
||||
+ mClass);
|
||||
}
|
||||
|
||||
return mClass.cast(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return NATIVE_SIZE_DYNAMIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateMarshalSize(T value) {
|
||||
int elementSize = mComponentMarshaler.getNativeSize();
|
||||
int arrayLength = Array.getLength(value);
|
||||
|
||||
if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
|
||||
// The fast way. Every element size is uniform.
|
||||
return elementSize * arrayLength;
|
||||
} else {
|
||||
// The slow way. Accumulate size for each element.
|
||||
int size = 0;
|
||||
for (int i = 0; i < arrayLength; ++i) {
|
||||
size += calculateElementMarshalSize(mComponentMarshaler, value, i);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers to avoid compiler errors regarding types with wildcards (?)
|
||||
*/
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler,
|
||||
ByteBuffer buffer, Object array, int index) {
|
||||
marshaler.marshal((TElem)Array.get(array, index), buffer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) {
|
||||
return arrayList.toArray((T[]) arrayDest);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler,
|
||||
Object array, int index) {
|
||||
Object elem = Array.get(array, index);
|
||||
|
||||
return marshaler.calculateMarshalSize((TElem) elem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
|
||||
return new MarshalerArray(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
|
||||
// support both ConcreteType[] and GenericType<ConcreteType>[]
|
||||
return managedType.getRawType().isArray();
|
||||
|
||||
// TODO: Should this recurse deeper and check that there is
|
||||
// a valid marshaler for the ConcreteType as well?
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshal booleans: TYPE_BYTE <-> boolean/Boolean
|
||||
*/
|
||||
public class MarshalQueryableBoolean implements MarshalQueryable<Boolean> {
|
||||
|
||||
private class MarshalerBoolean extends Marshaler<Boolean> {
|
||||
protected MarshalerBoolean(TypeReference<Boolean> typeReference, int nativeType) {
|
||||
super(MarshalQueryableBoolean.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Boolean value, ByteBuffer buffer) {
|
||||
boolean unboxValue = value;
|
||||
buffer.put((byte)(unboxValue ? 1 : 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean unmarshal(ByteBuffer buffer) {
|
||||
return buffer.get() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZEOF_BYTE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<Boolean> createMarshaler(TypeReference<Boolean> managedType,
|
||||
int nativeType) {
|
||||
return new MarshalerBoolean(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<Boolean> managedType, int nativeType) {
|
||||
return (Boolean.class.equals(managedType.getType())
|
||||
|| boolean.class.equals(managedType.getType())) && nativeType == TYPE_BYTE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.ColorSpaceTransform;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal {@link ColorSpaceTransform} to/from {@link #TYPE_RATIONAL}
|
||||
*/
|
||||
public class MarshalQueryableColorSpaceTransform implements
|
||||
MarshalQueryable<ColorSpaceTransform> {
|
||||
|
||||
private static final int ELEMENTS_INT32 = 3 * 3 * (SIZEOF_RATIONAL / SIZEOF_INT32);
|
||||
private static final int SIZE = SIZEOF_INT32 * ELEMENTS_INT32;
|
||||
|
||||
/** rational x 3 x 3 */
|
||||
private class MarshalerColorSpaceTransform extends Marshaler<ColorSpaceTransform> {
|
||||
protected MarshalerColorSpaceTransform(TypeReference<ColorSpaceTransform> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableColorSpaceTransform.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(ColorSpaceTransform value, ByteBuffer buffer) {
|
||||
int[] transformAsArray = new int[ELEMENTS_INT32];
|
||||
value.copyElements(transformAsArray, /*offset*/0);
|
||||
|
||||
for (int i = 0; i < ELEMENTS_INT32; ++i) {
|
||||
buffer.putInt(transformAsArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorSpaceTransform unmarshal(ByteBuffer buffer) {
|
||||
int[] transformAsArray = new int[ELEMENTS_INT32];
|
||||
|
||||
for (int i = 0; i < ELEMENTS_INT32; ++i) {
|
||||
transformAsArray[i] = buffer.getInt();
|
||||
}
|
||||
|
||||
return new ColorSpaceTransform(transformAsArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<ColorSpaceTransform> createMarshaler(
|
||||
TypeReference<ColorSpaceTransform> managedType, int nativeType) {
|
||||
return new MarshalerColorSpaceTransform(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(
|
||||
TypeReference<ColorSpaceTransform> managedType, int nativeType) {
|
||||
return nativeType == TYPE_RATIONAL &&
|
||||
ColorSpaceTransform.class.equals(managedType.getType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal any simple enum (0-arg constructors only) into/from either
|
||||
* {@code TYPE_BYTE} or {@code TYPE_INT32}.
|
||||
*
|
||||
* <p>Default values of the enum are mapped to its ordinal; this can be overridden
|
||||
* by providing a manual value with {@link #registerEnumValues}.</p>
|
||||
|
||||
* @param <T> the type of {@code Enum}
|
||||
*/
|
||||
public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable<T> {
|
||||
|
||||
private static final String TAG = MarshalQueryableEnum.class.getSimpleName();
|
||||
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private static final int UINT8_MIN = 0x0;
|
||||
private static final int UINT8_MAX = (1 << Byte.SIZE) - 1;
|
||||
private static final int UINT8_MASK = UINT8_MAX;
|
||||
|
||||
private class MarshalerEnum extends Marshaler<T> {
|
||||
|
||||
private final Class<T> mClass;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected MarshalerEnum(TypeReference<T> typeReference, int nativeType) {
|
||||
super(MarshalQueryableEnum.this, typeReference, nativeType);
|
||||
|
||||
mClass = (Class<T>)typeReference.getRawType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(T value, ByteBuffer buffer) {
|
||||
int enumValue = getEnumValue(value);
|
||||
|
||||
if (mNativeType == TYPE_INT32) {
|
||||
buffer.putInt(enumValue);
|
||||
} else if (mNativeType == TYPE_BYTE) {
|
||||
if (enumValue < UINT8_MIN || enumValue > UINT8_MAX) {
|
||||
throw new UnsupportedOperationException(String.format(
|
||||
"Enum value %x too large to fit into unsigned byte", enumValue));
|
||||
}
|
||||
buffer.put((byte)enumValue);
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T unmarshal(ByteBuffer buffer) {
|
||||
int enumValue;
|
||||
|
||||
switch (mNativeType) {
|
||||
case TYPE_INT32:
|
||||
enumValue = buffer.getInt();
|
||||
break;
|
||||
case TYPE_BYTE:
|
||||
// get the unsigned byte value; avoid sign extension
|
||||
enumValue = buffer.get() & UINT8_MASK;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError(
|
||||
"Unexpected native type; impossible since its not supported");
|
||||
}
|
||||
|
||||
return getEnumFromValue(mClass, enumValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return getPrimitiveTypeSize(mNativeType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
|
||||
return new MarshalerEnum(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
|
||||
if (nativeType == TYPE_INT32 || nativeType == TYPE_BYTE) {
|
||||
if (managedType.getType() instanceof Class<?>) {
|
||||
Class<?> typeClass = (Class<?>)managedType.getType();
|
||||
|
||||
if (typeClass.isEnum()) {
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "possible enum detected for " + typeClass);
|
||||
}
|
||||
|
||||
// The enum must not take extra arguments
|
||||
try {
|
||||
// match a class like: "public enum Fruits { Apple, Orange; }"
|
||||
typeClass.getDeclaredConstructor(String.class, int.class);
|
||||
return true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Skip: custom enum with a special constructor e.g. Foo(T), but need Foo()
|
||||
Log.e(TAG, "Can't marshal class " + typeClass + "; no default constructor");
|
||||
} catch (SecurityException e) {
|
||||
// Skip: wouldn't be able to touch the enum anyway
|
||||
Log.e(TAG, "Can't marshal class " + typeClass + "; not accessible");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
|
||||
new HashMap<Class<? extends Enum>, int[]>();
|
||||
|
||||
/**
|
||||
* Register a non-sequential set of values to be used with the marshal/unmarshal functions.
|
||||
*
|
||||
* <p>This enables get/set to correctly marshal the enum into a value that is C-compatible.</p>
|
||||
*
|
||||
* @param enumType The class for an enum
|
||||
* @param values A list of values mapping to the ordinals of the enum
|
||||
*/
|
||||
public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
|
||||
if (enumType.getEnumConstants().length != values.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected values array to be the same size as the enumTypes values "
|
||||
+ values.length + " for type " + enumType);
|
||||
}
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "Registered enum values for type " + enumType + " values");
|
||||
}
|
||||
|
||||
sEnumValues.put(enumType, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the numeric value from an enum.
|
||||
*
|
||||
* <p>This is usually the same as the ordinal value for
|
||||
* enums that have fully sequential values, although for C-style enums the range of values
|
||||
* may not map 1:1.</p>
|
||||
*
|
||||
* @param enumValue Enum instance
|
||||
* @return Int guaranteed to be ABI-compatible with the C enum equivalent
|
||||
*/
|
||||
private static <T extends Enum<T>> int getEnumValue(T enumValue) {
|
||||
int[] values;
|
||||
values = sEnumValues.get(enumValue.getClass());
|
||||
|
||||
int ordinal = enumValue.ordinal();
|
||||
if (values != null) {
|
||||
return values[ordinal];
|
||||
}
|
||||
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
|
||||
*
|
||||
* @param enumType Class of the enum we want to find
|
||||
* @param value The numeric value of the enum
|
||||
* @return An instance of the enum
|
||||
*/
|
||||
private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
|
||||
int ordinal;
|
||||
|
||||
int[] registeredValues = sEnumValues.get(enumType);
|
||||
if (registeredValues != null) {
|
||||
ordinal = -1;
|
||||
|
||||
for (int i = 0; i < registeredValues.length; ++i) {
|
||||
if (registeredValues[i] == value) {
|
||||
ordinal = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ordinal = value;
|
||||
}
|
||||
|
||||
T[] values = enumType.getEnumConstants();
|
||||
|
||||
if (ordinal < 0 || ordinal >= values.length) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Argument 'value' (%d) was not a valid enum value for type %s "
|
||||
+ "(registered? %b)",
|
||||
value,
|
||||
enumType, (registeredValues != null)));
|
||||
}
|
||||
|
||||
return values[ordinal];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.MeteringRectangle;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal {@link MeteringRectangle} to/from {@link #TYPE_INT32}
|
||||
*/
|
||||
public class MarshalQueryableMeteringRectangle implements MarshalQueryable<MeteringRectangle> {
|
||||
private static final int SIZE = SIZEOF_INT32 * 5;
|
||||
|
||||
/** (xmin, ymin, xmax, ymax, weight) */
|
||||
private class MarshalerMeteringRectangle extends Marshaler<MeteringRectangle> {
|
||||
protected MarshalerMeteringRectangle(TypeReference<MeteringRectangle> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableMeteringRectangle.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(MeteringRectangle value, ByteBuffer buffer) {
|
||||
int xMin = value.getX();
|
||||
int yMin = value.getY();
|
||||
int xMax = xMin + value.getWidth();
|
||||
int yMax = yMin + value.getHeight();
|
||||
int weight = value.getMeteringWeight();
|
||||
|
||||
buffer.putInt(xMin);
|
||||
buffer.putInt(yMin);
|
||||
buffer.putInt(xMax);
|
||||
buffer.putInt(yMax);
|
||||
buffer.putInt(weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeteringRectangle unmarshal(ByteBuffer buffer) {
|
||||
int xMin = buffer.getInt();
|
||||
int yMin = buffer.getInt();
|
||||
int xMax = buffer.getInt();
|
||||
int yMax = buffer.getInt();
|
||||
int weight = buffer.getInt();
|
||||
|
||||
int width = xMax - xMin;
|
||||
int height = yMax - yMin;
|
||||
|
||||
return new MeteringRectangle(xMin, yMin, width, height, weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<MeteringRectangle> createMarshaler(
|
||||
TypeReference<MeteringRectangle> managedType, int nativeType) {
|
||||
return new MarshalerMeteringRectangle(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(
|
||||
TypeReference<MeteringRectangle> managedType, int nativeType) {
|
||||
return nativeType == TYPE_INT32 && MeteringRectangle.class.equals(managedType.getType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshal fake native enums (ints): TYPE_BYTE <-> int/Integer
|
||||
*/
|
||||
public class MarshalQueryableNativeByteToInteger implements MarshalQueryable<Integer> {
|
||||
|
||||
private static final int UINT8_MASK = (1 << Byte.SIZE) - 1;
|
||||
|
||||
private class MarshalerNativeByteToInteger extends Marshaler<Integer> {
|
||||
protected MarshalerNativeByteToInteger(TypeReference<Integer> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableNativeByteToInteger.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Integer value, ByteBuffer buffer) {
|
||||
buffer.put((byte)(int)value); // truncate down to byte
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer unmarshal(ByteBuffer buffer) {
|
||||
// expand unsigned byte to int; avoid sign extension
|
||||
return buffer.get() & UINT8_MASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZEOF_BYTE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<Integer> createMarshaler(TypeReference<Integer> managedType,
|
||||
int nativeType) {
|
||||
return new MarshalerNativeByteToInteger(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<Integer> managedType, int nativeType) {
|
||||
return (Integer.class.equals(managedType.getType())
|
||||
|| int.class.equals(managedType.getType())) && nativeType == TYPE_BYTE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal any {@code T extends Parcelable} to/from any native type
|
||||
*
|
||||
* <p>Use with extreme caution! File descriptors and binders will not be marshaled across.</p>
|
||||
*/
|
||||
public class MarshalQueryableParcelable<T extends Parcelable>
|
||||
implements MarshalQueryable<T> {
|
||||
|
||||
private static final String TAG = "MarshalParcelable";
|
||||
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private static final String FIELD_CREATOR = "CREATOR";
|
||||
|
||||
private class MarshalerParcelable extends Marshaler<T> {
|
||||
|
||||
private final Class<T> mClass;
|
||||
private final Parcelable.Creator<T> mCreator;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected MarshalerParcelable(TypeReference<T> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableParcelable.this, typeReference, nativeType);
|
||||
|
||||
mClass = (Class<T>)typeReference.getRawType();
|
||||
Field creatorField;
|
||||
try {
|
||||
creatorField = mClass.getDeclaredField(FIELD_CREATOR);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Impossible. All Parcelable implementations must have a 'CREATOR' static field
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
try {
|
||||
mCreator = (Parcelable.Creator<T>)creatorField.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Impossible: All 'CREATOR' static fields must be public
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Impossible: This is a static field, so null must be ok
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(T value, ByteBuffer buffer) {
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "marshal " + value);
|
||||
}
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
byte[] parcelContents;
|
||||
|
||||
try {
|
||||
value.writeToParcel(parcel, /*flags*/0);
|
||||
|
||||
if (parcel.hasFileDescriptors()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Parcelable " + value + " must not have file descriptors");
|
||||
}
|
||||
|
||||
parcelContents = parcel.marshall();
|
||||
}
|
||||
finally {
|
||||
parcel.recycle();
|
||||
}
|
||||
|
||||
if (parcelContents.length == 0) {
|
||||
throw new AssertionError("No data marshaled for " + value);
|
||||
}
|
||||
|
||||
buffer.put(parcelContents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T unmarshal(ByteBuffer buffer) {
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining());
|
||||
}
|
||||
|
||||
/*
|
||||
* Quadratically slow when marshaling an array of parcelables.
|
||||
*
|
||||
* Read out the entire byte buffer as an array, then copy it into the parcel.
|
||||
*
|
||||
* Once we unparcel the entire object, advance the byte buffer by only how many
|
||||
* bytes the parcel actually used up.
|
||||
*
|
||||
* Future: If we ever do need to use parcelable arrays, we can do this a little smarter
|
||||
* by reading out a chunk like 4,8,16,24 each time, but not sure how to detect
|
||||
* parcels being too short in this case.
|
||||
*
|
||||
* Future: Alternatively use Parcel#obtain(long) directly into the native
|
||||
* pointer of a ByteBuffer, which would not copy if the ByteBuffer was direct.
|
||||
*/
|
||||
buffer.mark();
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
try {
|
||||
int maxLength = buffer.remaining();
|
||||
|
||||
byte[] remaining = new byte[maxLength];
|
||||
buffer.get(remaining);
|
||||
|
||||
parcel.unmarshall(remaining, /*offset*/0, maxLength);
|
||||
parcel.setDataPosition(/*pos*/0);
|
||||
|
||||
T value = mCreator.createFromParcel(parcel);
|
||||
int actualLength = parcel.dataPosition();
|
||||
|
||||
if (actualLength == 0) {
|
||||
throw new AssertionError("No data marshaled for " + value);
|
||||
}
|
||||
|
||||
// set the position past the bytes the parcelable actually used
|
||||
buffer.reset();
|
||||
buffer.position(buffer.position() + actualLength);
|
||||
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "unmarshal, parcel length was " + actualLength);
|
||||
Log.v(TAG, "unmarshal, value is " + value);
|
||||
}
|
||||
|
||||
return mClass.cast(value);
|
||||
} finally {
|
||||
parcel.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return NATIVE_SIZE_DYNAMIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateMarshalSize(T value) {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
try {
|
||||
value.writeToParcel(parcel, /*flags*/0);
|
||||
int length = parcel.marshall().length;
|
||||
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "calculateMarshalSize, length when parceling "
|
||||
+ value + " is " + length);
|
||||
}
|
||||
|
||||
return length;
|
||||
} finally {
|
||||
parcel.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
|
||||
return new MarshalerParcelable(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
|
||||
return Parcelable.class.isAssignableFrom(managedType.getRawType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.Rational;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshal/unmarshal built-in primitive types to and from a {@link ByteBuffer}.
|
||||
*
|
||||
* <p>The following list of type marshaling is supported:
|
||||
* <ul>
|
||||
* <li>byte <-> TYPE_BYTE
|
||||
* <li>int <-> TYPE_INT32
|
||||
* <li>long <-> TYPE_INT64
|
||||
* <li>float <-> TYPE_FLOAT
|
||||
* <li>double <-> TYPE_DOUBLE
|
||||
* <li>Rational <-> TYPE_RATIONAL
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* <p>Due to the nature of generics, values are always boxed; this also means that both
|
||||
* the boxed and unboxed types are supported (i.e. both {@code int} and {@code Integer}).</p>
|
||||
*
|
||||
* <p>Each managed type <!--(other than boolean)--> must correspond 1:1 to the native type
|
||||
* (e.g. a byte will not map to a {@link CameraMetadataNative#TYPE_INT32 TYPE_INT32} or vice versa)
|
||||
* for marshaling.</p>
|
||||
*/
|
||||
public final class MarshalQueryablePrimitive<T> implements MarshalQueryable<T> {
|
||||
|
||||
private class MarshalerPrimitive extends Marshaler<T> {
|
||||
/** Always the wrapped class variant of the primitive class for {@code T} */
|
||||
private final Class<T> mClass;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected MarshalerPrimitive(TypeReference<T> typeReference, int nativeType) {
|
||||
super(MarshalQueryablePrimitive.this, typeReference, nativeType);
|
||||
|
||||
// Turn primitives into wrappers, otherwise int.class.cast(Integer) will fail
|
||||
mClass = wrapClassIfPrimitive((Class<T>)typeReference.getRawType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T unmarshal(ByteBuffer buffer) {
|
||||
return mClass.cast(unmarshalObject(buffer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateMarshalSize(T value) {
|
||||
return getPrimitiveTypeSize(mNativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(T value, ByteBuffer buffer) {
|
||||
if (value instanceof Integer) {
|
||||
checkNativeTypeEquals(TYPE_INT32, mNativeType);
|
||||
final int val = (Integer) value;
|
||||
marshalPrimitive(val, buffer);
|
||||
} else if (value instanceof Float) {
|
||||
checkNativeTypeEquals(TYPE_FLOAT, mNativeType);
|
||||
final float val = (Float) value;
|
||||
marshalPrimitive(val, buffer);
|
||||
} else if (value instanceof Long) {
|
||||
checkNativeTypeEquals(TYPE_INT64, mNativeType);
|
||||
final long val = (Long) value;
|
||||
marshalPrimitive(val, buffer);
|
||||
} else if (value instanceof Rational) {
|
||||
checkNativeTypeEquals(TYPE_RATIONAL, mNativeType);
|
||||
marshalPrimitive((Rational) value, buffer);
|
||||
} else if (value instanceof Double) {
|
||||
checkNativeTypeEquals(TYPE_DOUBLE, mNativeType);
|
||||
final double val = (Double) value;
|
||||
marshalPrimitive(val, buffer);
|
||||
} else if (value instanceof Byte) {
|
||||
checkNativeTypeEquals(TYPE_BYTE, mNativeType);
|
||||
final byte val = (Byte) value;
|
||||
marshalPrimitive(val, buffer);
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"Can't marshal managed type " + mTypeReference);
|
||||
}
|
||||
}
|
||||
|
||||
private void marshalPrimitive(int value, ByteBuffer buffer) {
|
||||
buffer.putInt(value);
|
||||
}
|
||||
|
||||
private void marshalPrimitive(float value, ByteBuffer buffer) {
|
||||
buffer.putFloat(value);
|
||||
}
|
||||
|
||||
private void marshalPrimitive(double value, ByteBuffer buffer) {
|
||||
buffer.putDouble(value);
|
||||
}
|
||||
|
||||
private void marshalPrimitive(long value, ByteBuffer buffer) {
|
||||
buffer.putLong(value);
|
||||
}
|
||||
|
||||
private void marshalPrimitive(Rational value, ByteBuffer buffer) {
|
||||
buffer.putInt(value.getNumerator());
|
||||
buffer.putInt(value.getDenominator());
|
||||
}
|
||||
|
||||
private void marshalPrimitive(byte value, ByteBuffer buffer) {
|
||||
buffer.put(value);
|
||||
}
|
||||
|
||||
private Object unmarshalObject(ByteBuffer buffer) {
|
||||
switch (mNativeType) {
|
||||
case TYPE_INT32:
|
||||
return buffer.getInt();
|
||||
case TYPE_FLOAT:
|
||||
return buffer.getFloat();
|
||||
case TYPE_INT64:
|
||||
return buffer.getLong();
|
||||
case TYPE_RATIONAL:
|
||||
int numerator = buffer.getInt();
|
||||
int denominator = buffer.getInt();
|
||||
return new Rational(numerator, denominator);
|
||||
case TYPE_DOUBLE:
|
||||
return buffer.getDouble();
|
||||
case TYPE_BYTE:
|
||||
return buffer.get(); // getByte
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"Can't unmarshal native type " + mNativeType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return getPrimitiveTypeSize(mNativeType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
|
||||
return new MarshalerPrimitive(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
|
||||
if (managedType.getType() instanceof Class<?>) {
|
||||
Class<?> klass = (Class<?>)managedType.getType();
|
||||
|
||||
if (klass == byte.class || klass == Byte.class) {
|
||||
return nativeType == TYPE_BYTE;
|
||||
} else if (klass == int.class || klass == Integer.class) {
|
||||
return nativeType == TYPE_INT32;
|
||||
} else if (klass == float.class || klass == Float.class) {
|
||||
return nativeType == TYPE_FLOAT;
|
||||
} else if (klass == long.class || klass == Long.class) {
|
||||
return nativeType == TYPE_INT64;
|
||||
} else if (klass == double.class || klass == Double.class) {
|
||||
return nativeType == TYPE_DOUBLE;
|
||||
} else if (klass == Rational.class) {
|
||||
return nativeType == TYPE_RATIONAL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.marshal.MarshalRegistry;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.util.Range;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal {@link Range} to/from any native type
|
||||
*/
|
||||
public class MarshalQueryableRange<T extends Comparable<? super T>>
|
||||
implements MarshalQueryable<Range<T>> {
|
||||
private static final int RANGE_COUNT = 2;
|
||||
|
||||
private class MarshalerRange extends Marshaler<Range<T>> {
|
||||
private final Class<? super Range<T>> mClass;
|
||||
private final Constructor<Range<T>> mConstructor;
|
||||
/** Marshal the {@code T} inside of {@code Range<T>} */
|
||||
private final Marshaler<T> mNestedTypeMarshaler;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected MarshalerRange(TypeReference<Range<T>> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableRange.this, typeReference, nativeType);
|
||||
|
||||
mClass = typeReference.getRawType();
|
||||
|
||||
/*
|
||||
* Lookup the actual type argument, e.g. Range<Integer> --> Integer
|
||||
* and then get the marshaler for that managed type.
|
||||
*/
|
||||
ParameterizedType paramType;
|
||||
try {
|
||||
paramType = (ParameterizedType) typeReference.getType();
|
||||
} catch (ClassCastException e) {
|
||||
throw new AssertionError("Raw use of Range is not supported", e);
|
||||
}
|
||||
Type actualTypeArgument = paramType.getActualTypeArguments()[0];
|
||||
|
||||
TypeReference<?> actualTypeArgToken =
|
||||
TypeReference.createSpecializedTypeReference(actualTypeArgument);
|
||||
|
||||
mNestedTypeMarshaler = (Marshaler<T>)MarshalRegistry.getMarshaler(
|
||||
actualTypeArgToken, mNativeType);
|
||||
try {
|
||||
mConstructor = (Constructor<Range<T>>)mClass.getConstructor(
|
||||
Comparable.class, Comparable.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Range<T> value, ByteBuffer buffer) {
|
||||
mNestedTypeMarshaler.marshal(value.getLower(), buffer);
|
||||
mNestedTypeMarshaler.marshal(value.getUpper(), buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<T> unmarshal(ByteBuffer buffer) {
|
||||
T lower = mNestedTypeMarshaler.unmarshal(buffer);
|
||||
T upper = mNestedTypeMarshaler.unmarshal(buffer);
|
||||
|
||||
try {
|
||||
return mConstructor.newInstance(lower, upper);
|
||||
} catch (InstantiationException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
int nestedSize = mNestedTypeMarshaler.getNativeSize();
|
||||
|
||||
if (nestedSize != NATIVE_SIZE_DYNAMIC) {
|
||||
return nestedSize * RANGE_COUNT;
|
||||
} else {
|
||||
return NATIVE_SIZE_DYNAMIC;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateMarshalSize(Range<T> value) {
|
||||
int nativeSize = getNativeSize();
|
||||
|
||||
if (nativeSize != NATIVE_SIZE_DYNAMIC) {
|
||||
return nativeSize;
|
||||
} else {
|
||||
int lowerSize = mNestedTypeMarshaler.calculateMarshalSize(value.getLower());
|
||||
int upperSize = mNestedTypeMarshaler.calculateMarshalSize(value.getUpper());
|
||||
|
||||
return lowerSize + upperSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<Range<T>> createMarshaler(TypeReference<Range<T>> managedType,
|
||||
int nativeType) {
|
||||
return new MarshalerRange(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<Range<T>> managedType, int nativeType) {
|
||||
return (Range.class.equals(managedType.getRawType()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal {@link Rect} to/from {@link #TYPE_INT32}
|
||||
*/
|
||||
public class MarshalQueryableRect implements MarshalQueryable<Rect> {
|
||||
private static final int SIZE = SIZEOF_INT32 * 4;
|
||||
|
||||
private class MarshalerRect extends Marshaler<Rect> {
|
||||
protected MarshalerRect(TypeReference<Rect> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableRect.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Rect value, ByteBuffer buffer) {
|
||||
buffer.putInt(value.left);
|
||||
buffer.putInt(value.top);
|
||||
buffer.putInt(value.width());
|
||||
buffer.putInt(value.height());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rect unmarshal(ByteBuffer buffer) {
|
||||
int left = buffer.getInt();
|
||||
int top = buffer.getInt();
|
||||
int width = buffer.getInt();
|
||||
int height = buffer.getInt();
|
||||
|
||||
int right = left + width;
|
||||
int bottom = top + height;
|
||||
|
||||
return new Rect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<Rect> createMarshaler(TypeReference<Rect> managedType, int nativeType) {
|
||||
return new MarshalerRect(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<Rect> managedType, int nativeType) {
|
||||
return nativeType == TYPE_INT32 && (Rect.class.equals(managedType.getType()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.ReprocessFormatsMap;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
/**
|
||||
* Marshaler for {@code android.scaler.availableInputOutputFormatsMap} custom class
|
||||
* {@link ReprocessFormatsMap}
|
||||
*/
|
||||
public class MarshalQueryableReprocessFormatsMap
|
||||
implements MarshalQueryable<ReprocessFormatsMap> {
|
||||
|
||||
private class MarshalerReprocessFormatsMap extends Marshaler<ReprocessFormatsMap> {
|
||||
protected MarshalerReprocessFormatsMap(
|
||||
TypeReference<ReprocessFormatsMap> typeReference, int nativeType) {
|
||||
super(MarshalQueryableReprocessFormatsMap.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(ReprocessFormatsMap value, ByteBuffer buffer) {
|
||||
/*
|
||||
* // writing (static example, DNG+ZSL)
|
||||
* int32_t[] contents = {
|
||||
* RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
|
||||
* RAW16, 2, YUV_420_888, BLOB,
|
||||
* ...,
|
||||
* INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
|
||||
* };
|
||||
*/
|
||||
int[] inputs = value.getInputs();
|
||||
for (int input : inputs) {
|
||||
// INPUT_FORMAT
|
||||
buffer.putInt(input);
|
||||
|
||||
int[] outputs = value.getOutputs(input);
|
||||
// OUTPUT_FORMAT_COUNT
|
||||
buffer.putInt(outputs.length);
|
||||
|
||||
// [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
|
||||
for (int output : outputs) {
|
||||
buffer.putInt(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReprocessFormatsMap unmarshal(ByteBuffer buffer) {
|
||||
int len = buffer.remaining() / SIZEOF_INT32;
|
||||
if (buffer.remaining() % SIZEOF_INT32 != 0) {
|
||||
throw new AssertionError("ReprocessFormatsMap was not TYPE_INT32");
|
||||
}
|
||||
|
||||
int[] entries = new int[len];
|
||||
|
||||
IntBuffer intBuffer = buffer.asIntBuffer();
|
||||
intBuffer.get(entries);
|
||||
|
||||
// TODO: consider moving rest of parsing code from ReprocessFormatsMap to here
|
||||
|
||||
return new ReprocessFormatsMap(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return NATIVE_SIZE_DYNAMIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateMarshalSize(ReprocessFormatsMap value) {
|
||||
/*
|
||||
* // writing (static example, DNG+ZSL)
|
||||
* int32_t[] contents = {
|
||||
* RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
|
||||
* RAW16, 2, YUV_420_888, BLOB,
|
||||
* ...,
|
||||
* INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
|
||||
* };
|
||||
*/
|
||||
int length = 0;
|
||||
|
||||
int[] inputs = value.getInputs();
|
||||
for (int input : inputs) {
|
||||
|
||||
length += 1; // INPUT_FORMAT
|
||||
length += 1; // OUTPUT_FORMAT_COUNT
|
||||
|
||||
int[] outputs = value.getOutputs(input);
|
||||
length += outputs.length; // [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
|
||||
}
|
||||
|
||||
return length * SIZEOF_INT32;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<ReprocessFormatsMap> createMarshaler(
|
||||
TypeReference<ReprocessFormatsMap> managedType, int nativeType) {
|
||||
return new MarshalerReprocessFormatsMap(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<ReprocessFormatsMap> managedType,
|
||||
int nativeType) {
|
||||
return nativeType == TYPE_INT32 && managedType.getType().equals(ReprocessFormatsMap.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.RggbChannelVector;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
/**
|
||||
* Marshal {@link RggbChannelVector} to/from {@link #TYPE_FLOAT} {@code x 4}
|
||||
*/
|
||||
public class MarshalQueryableRggbChannelVector implements MarshalQueryable<RggbChannelVector> {
|
||||
private static final int SIZE = SIZEOF_FLOAT * RggbChannelVector.COUNT;
|
||||
|
||||
private class MarshalerRggbChannelVector extends Marshaler<RggbChannelVector> {
|
||||
protected MarshalerRggbChannelVector(TypeReference<RggbChannelVector> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableRggbChannelVector.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(RggbChannelVector value, ByteBuffer buffer) {
|
||||
for (int i = 0; i < RggbChannelVector.COUNT; ++i) {
|
||||
buffer.putFloat(value.getComponent(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RggbChannelVector unmarshal(ByteBuffer buffer) {
|
||||
float red = buffer.getFloat();
|
||||
float gEven = buffer.getFloat();
|
||||
float gOdd = buffer.getFloat();
|
||||
float blue = buffer.getFloat();
|
||||
|
||||
return new RggbChannelVector(red, gEven, gOdd, blue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<RggbChannelVector> createMarshaler(
|
||||
TypeReference<RggbChannelVector> managedType, int nativeType) {
|
||||
return new MarshalerRggbChannelVector(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(
|
||||
TypeReference<RggbChannelVector> managedType, int nativeType) {
|
||||
return nativeType == TYPE_FLOAT && (RggbChannelVector.class.equals(managedType.getType()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.Size;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshal {@link Size} to/from {@code TYPE_INT32}
|
||||
*/
|
||||
public class MarshalQueryableSize implements MarshalQueryable<Size> {
|
||||
private static final int SIZE = SIZEOF_INT32 * 2;
|
||||
|
||||
private class MarshalerSize extends Marshaler<Size> {
|
||||
protected MarshalerSize(TypeReference<Size> typeReference, int nativeType) {
|
||||
super(MarshalQueryableSize.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Size value, ByteBuffer buffer) {
|
||||
buffer.putInt(value.getWidth());
|
||||
buffer.putInt(value.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size unmarshal(ByteBuffer buffer) {
|
||||
int width = buffer.getInt();
|
||||
int height = buffer.getInt();
|
||||
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<Size> createMarshaler(TypeReference<Size> managedType, int nativeType) {
|
||||
return new MarshalerSize(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<Size> managedType, int nativeType) {
|
||||
return nativeType == TYPE_INT32 && (Size.class.equals(managedType.getType()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.util.SizeF;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshal {@link SizeF} to/from {@code TYPE_FLOAT}
|
||||
*/
|
||||
public class MarshalQueryableSizeF implements MarshalQueryable<SizeF> {
|
||||
|
||||
private static final int SIZE = SIZEOF_FLOAT * 2;
|
||||
|
||||
private class MarshalerSizeF extends Marshaler<SizeF> {
|
||||
|
||||
protected MarshalerSizeF(TypeReference<SizeF> typeReference, int nativeType) {
|
||||
super(MarshalQueryableSizeF.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(SizeF value, ByteBuffer buffer) {
|
||||
buffer.putFloat(value.getWidth());
|
||||
buffer.putFloat(value.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SizeF unmarshal(ByteBuffer buffer) {
|
||||
float width = buffer.getFloat();
|
||||
float height = buffer.getFloat();
|
||||
|
||||
return new SizeF(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<SizeF> createMarshaler(
|
||||
TypeReference<SizeF> managedType, int nativeType) {
|
||||
return new MarshalerSizeF(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<SizeF> managedType, int nativeType) {
|
||||
return nativeType == TYPE_FLOAT && (SizeF.class.equals(managedType.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.StreamConfiguration;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshaler for {@code android.scaler.availableStreamConfigurations} custom class
|
||||
* {@link StreamConfiguration}
|
||||
*
|
||||
* <p>Data is stored as {@code (format, width, height, input?)} tuples (int32).</p>
|
||||
*/
|
||||
public class MarshalQueryableStreamConfiguration
|
||||
implements MarshalQueryable<StreamConfiguration> {
|
||||
private static final int SIZE = SIZEOF_INT32 * 4;
|
||||
|
||||
private class MarshalerStreamConfiguration extends Marshaler<StreamConfiguration> {
|
||||
protected MarshalerStreamConfiguration(TypeReference<StreamConfiguration> typeReference,
|
||||
int nativeType) {
|
||||
super(MarshalQueryableStreamConfiguration.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(StreamConfiguration value, ByteBuffer buffer) {
|
||||
buffer.putInt(value.getFormat());
|
||||
buffer.putInt(value.getWidth());
|
||||
buffer.putInt(value.getHeight());
|
||||
buffer.putInt(value.isInput() ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamConfiguration unmarshal(ByteBuffer buffer) {
|
||||
int format = buffer.getInt();
|
||||
int width = buffer.getInt();
|
||||
int height = buffer.getInt();
|
||||
boolean input = buffer.getInt() != 0;
|
||||
|
||||
return new StreamConfiguration(format, width, height, input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<StreamConfiguration> createMarshaler(
|
||||
TypeReference<StreamConfiguration> managedType, int nativeType) {
|
||||
return new MarshalerStreamConfiguration(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<StreamConfiguration> managedType,
|
||||
int nativeType) {
|
||||
return nativeType == TYPE_INT32 && managedType.getType().equals(StreamConfiguration.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.StreamConfigurationDuration;
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static android.hardware.camera2.marshal.MarshalHelpers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Marshaler for custom class {@link StreamConfigurationDuration} for min-frame and stall durations.
|
||||
*
|
||||
* <p>
|
||||
* Data is stored as {@code (format, width, height, durationNs)} tuples (int64).
|
||||
* </p>
|
||||
*/
|
||||
public class MarshalQueryableStreamConfigurationDuration
|
||||
implements MarshalQueryable<StreamConfigurationDuration> {
|
||||
|
||||
private static final int SIZE = SIZEOF_INT64 * 4;
|
||||
/**
|
||||
* Values and-ed with this will do an unsigned int to signed long conversion;
|
||||
* in other words the sign bit from the int will not be extended.
|
||||
* */
|
||||
private static final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
|
||||
|
||||
private class MarshalerStreamConfigurationDuration
|
||||
extends Marshaler<StreamConfigurationDuration> {
|
||||
|
||||
protected MarshalerStreamConfigurationDuration(
|
||||
TypeReference<StreamConfigurationDuration> typeReference, int nativeType) {
|
||||
super(MarshalQueryableStreamConfigurationDuration.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(StreamConfigurationDuration value, ByteBuffer buffer) {
|
||||
buffer.putLong(value.getFormat() & MASK_UNSIGNED_INT); // unsigned int -> long
|
||||
buffer.putLong(value.getWidth());
|
||||
buffer.putLong(value.getHeight());
|
||||
buffer.putLong(value.getDuration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamConfigurationDuration unmarshal(ByteBuffer buffer) {
|
||||
int format = (int)buffer.getLong();
|
||||
int width = (int)buffer.getLong();
|
||||
int height = (int)buffer.getLong();
|
||||
long durationNs = buffer.getLong();
|
||||
|
||||
return new StreamConfigurationDuration(format, width, height, durationNs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<StreamConfigurationDuration> createMarshaler(
|
||||
TypeReference<StreamConfigurationDuration> managedType, int nativeType) {
|
||||
return new MarshalerStreamConfigurationDuration(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<StreamConfigurationDuration> managedType,
|
||||
int nativeType) {
|
||||
return nativeType == TYPE_INT64 &&
|
||||
(StreamConfigurationDuration.class.equals(managedType.getType()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.marshal.impl;
|
||||
|
||||
import android.hardware.camera2.marshal.Marshaler;
|
||||
import android.hardware.camera2.marshal.MarshalQueryable;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
|
||||
/**
|
||||
* Marshal {@link String} to/from {@link #TYPE_BYTE}.
|
||||
*/
|
||||
public class MarshalQueryableString implements MarshalQueryable<String> {
|
||||
|
||||
private static final String TAG = MarshalQueryableString.class.getSimpleName();
|
||||
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
|
||||
private static final byte NUL = (byte)'\0'; // used as string terminator
|
||||
|
||||
private class MarshalerString extends Marshaler<String> {
|
||||
|
||||
protected MarshalerString(TypeReference<String> typeReference, int nativeType) {
|
||||
super(MarshalQueryableString.this, typeReference, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(String value, ByteBuffer buffer) {
|
||||
byte[] arr = value.getBytes(UTF8_CHARSET);
|
||||
|
||||
buffer.put(arr);
|
||||
buffer.put(NUL); // metadata strings are NUL-terminated
|
||||
}
|
||||
|
||||
@Override
|
||||
public int calculateMarshalSize(String value) {
|
||||
byte[] arr = value.getBytes(UTF8_CHARSET);
|
||||
|
||||
return arr.length + 1; // metadata strings are NUL-terminated
|
||||
}
|
||||
|
||||
@Override
|
||||
public String unmarshal(ByteBuffer buffer) {
|
||||
buffer.mark(); // save the current position
|
||||
|
||||
boolean foundNull = false;
|
||||
int stringLength = 0;
|
||||
while (buffer.hasRemaining()) {
|
||||
if (buffer.get() == NUL) {
|
||||
foundNull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
stringLength++;
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG,
|
||||
"unmarshal - scanned " + stringLength + " characters; found null? "
|
||||
+ foundNull);
|
||||
}
|
||||
|
||||
if (!foundNull) {
|
||||
throw new UnsupportedOperationException("Strings must be null-terminated");
|
||||
}
|
||||
|
||||
buffer.reset(); // go back to the previously marked position
|
||||
|
||||
byte[] strBytes = new byte[stringLength + 1];
|
||||
buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
|
||||
|
||||
// not including null character
|
||||
return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNativeSize() {
|
||||
return NATIVE_SIZE_DYNAMIC;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Marshaler<String> createMarshaler(
|
||||
TypeReference<String> managedType, int nativeType) {
|
||||
return new MarshalerString(managedType, nativeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTypeMappingSupported(TypeReference<String> managedType, int nativeType) {
|
||||
return nativeType == TYPE_BYTE && String.class.equals(managedType.getType());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
{@hide}
|
||||
</body>
|
||||
3
core/java/android/hardware/camera2/marshal/package.html
Normal file
3
core/java/android/hardware/camera2/marshal/package.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
{@hide}
|
||||
</body>
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.hardware.camera2.impl;
|
||||
package android.hardware.camera2.utils;
|
||||
|
||||
/**
|
||||
* Provide hashing functions using the Modified Bernstein hash
|
||||
435
core/java/android/hardware/camera2/utils/TypeReference.java
Normal file
435
core/java/android/hardware/camera2/utils/TypeReference.java
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.hardware.camera2.utils;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Super type token; allows capturing generic types at runtime by forcing them to be reified.
|
||||
*
|
||||
* <p>Usage example: <pre>{@code
|
||||
* // using anonymous classes (preferred)
|
||||
* TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
|
||||
*
|
||||
* // using named classes
|
||||
* class IntTypeReference extends TypeReference<Integer> {...}
|
||||
* TypeReference<Integer> intToken = new IntTypeReference();
|
||||
* }</p></pre>
|
||||
*
|
||||
* <p>Unlike the reference implementation, this bans nested TypeVariables; that is all
|
||||
* dynamic types must equal to the static types.</p>
|
||||
*
|
||||
* <p>See <a href="http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html">
|
||||
* http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html</a>
|
||||
* for more details.</p>
|
||||
*/
|
||||
public abstract class TypeReference<T> {
|
||||
private final Type mType;
|
||||
|
||||
/**
|
||||
* Create a new type reference for {@code T}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code T}'s actual type contains a type variable
|
||||
*
|
||||
* @see TypeReference
|
||||
*/
|
||||
protected TypeReference() {
|
||||
ParameterizedType thisType = (ParameterizedType)getClass().getGenericSuperclass();
|
||||
|
||||
// extract the "T" from TypeReference<T>
|
||||
mType = thisType.getActualTypeArguments()[0];
|
||||
|
||||
/*
|
||||
* Prohibit type references with type variables such as
|
||||
*
|
||||
* class GenericListToken<T> extends TypeReference<List<T>>
|
||||
*
|
||||
* Since the "T" there is not known without an instance of T, type equality would
|
||||
* consider *all* Lists equal regardless of T. Allowing this would defeat
|
||||
* some of the type safety of a type reference.
|
||||
*/
|
||||
if (containsTypeVariable(mType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Including a type variable in a type reference is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dynamic {@link Type} corresponding to the captured type {@code T}.
|
||||
*/
|
||||
public Type getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
private TypeReference(Type type) {
|
||||
mType = type;
|
||||
|
||||
if (containsTypeVariable(mType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Including a type variable in a type reference is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
private static class SpecializedTypeReference<T> extends TypeReference<T> {
|
||||
public SpecializedTypeReference(Class<T> klass) {
|
||||
super(klass);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class SpecializedBaseTypeReference extends TypeReference {
|
||||
public SpecializedBaseTypeReference(Type type) {
|
||||
super(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a specialized type reference from a dynamic class instance,
|
||||
* bypassing the standard compile-time checks.
|
||||
*
|
||||
* <p>As with a regular type reference, the {@code klass} must not contain
|
||||
* any type variables.</p>
|
||||
*
|
||||
* @param klass a non-{@code null} {@link Class} instance
|
||||
*
|
||||
* @return a type reference which captures {@code T} at runtime
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code T} had any type variables
|
||||
*/
|
||||
public static <T> TypeReference<T> createSpecializedTypeReference(Class<T> klass) {
|
||||
return new SpecializedTypeReference<T>(klass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a specialized type reference from a dynamic {@link Type} instance,
|
||||
* bypassing the standard compile-time checks.
|
||||
*
|
||||
* <p>As with a regular type reference, the {@code type} must not contain
|
||||
* any type variables.</p>
|
||||
*
|
||||
* @param type a non-{@code null} {@link Type} instance
|
||||
*
|
||||
* @return a type reference which captures {@code T} at runtime
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code type} had any type variables
|
||||
*/
|
||||
public static TypeReference<?> createSpecializedTypeReference(Type type) {
|
||||
return new SpecializedBaseTypeReference(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw type of T.
|
||||
*
|
||||
* <p><ul>
|
||||
* <li>If T is a Class itself, T itself is returned.
|
||||
* <li>If T is a ParameterizedType, the raw type of the parameterized type is returned.
|
||||
* <li>If T is a GenericArrayType, the returned type is the corresponding array class.
|
||||
* For example: {@code List<Integer>[]} => {@code List[]}.
|
||||
* <li>If T is a type variable or a wildcard type, the raw type of the first upper bound is
|
||||
* returned. For example: {@code <X extends Foo>} => {@code Foo}.
|
||||
* </ul>
|
||||
*
|
||||
* @return the raw type of {@code T}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final Class<? super T> getRawType() {
|
||||
return (Class<? super T>)getRawType(mType);
|
||||
}
|
||||
|
||||
private static final Class<?> getRawType(Type type) {
|
||||
if (type == null) {
|
||||
throw new NullPointerException("type must not be null");
|
||||
}
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
return (Class<?>)type;
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
return (Class<?>)(((ParameterizedType)type).getRawType());
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
return getArrayClass(getRawType(((GenericArrayType)type).getGenericComponentType()));
|
||||
} else if (type instanceof WildcardType) {
|
||||
// Should be at most 1 upper bound, but treat it like an array for simplicity
|
||||
return getRawType(((WildcardType) type).getUpperBounds());
|
||||
} else if (type instanceof TypeVariable) {
|
||||
throw new AssertionError("Type variables are not allowed in type references");
|
||||
} else {
|
||||
// Impossible
|
||||
throw new AssertionError("Unhandled branch to get raw type for type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class<?> getRawType(Type[] types) {
|
||||
if (types == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Type type : types) {
|
||||
Class<?> klass = getRawType(type);
|
||||
if (klass != null) {
|
||||
return klass;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final Class<?> getArrayClass(Class<?> componentType) {
|
||||
return Array.newInstance(componentType, 0).getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the component type, e.g. {@code T} from {@code T[]}.
|
||||
*
|
||||
* @return component type, or {@code null} if {@code T} is not an array
|
||||
*/
|
||||
public TypeReference<?> getComponentType() {
|
||||
Type componentType = getComponentType(mType);
|
||||
|
||||
return (componentType != null) ?
|
||||
createSpecializedTypeReference(componentType) :
|
||||
null;
|
||||
}
|
||||
|
||||
private static Type getComponentType(Type type) {
|
||||
checkNotNull(type, "type must not be null");
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
return ((Class<?>) type).getComponentType();
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
return null;
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
return ((GenericArrayType)type).getGenericComponentType();
|
||||
} else if (type instanceof WildcardType) {
|
||||
// Should be at most 1 upper bound, but treat it like an array for simplicity
|
||||
throw new UnsupportedOperationException("TODO: support wild card components");
|
||||
} else if (type instanceof TypeVariable) {
|
||||
throw new AssertionError("Type variables are not allowed in type references");
|
||||
} else {
|
||||
// Impossible
|
||||
throw new AssertionError("Unhandled branch to get component type for type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two objects for equality.
|
||||
*
|
||||
* <p>A TypeReference is only equal to another TypeReference if their captured type {@code T}
|
||||
* is also equal.</p>
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// Note that this comparison could inaccurately return true when comparing types
|
||||
// with nested type variables; therefore we ban type variables in the constructor.
|
||||
return o instanceof TypeReference<?> && mType.equals(((TypeReference<?>)o).mType);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mType.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the {@code type} contains a {@link TypeVariable} recursively.
|
||||
*
|
||||
* <p>Intuitively, a type variable is a type in a type expression that refers to a generic
|
||||
* type which is not known at the definition of the expression (commonly seen when
|
||||
* type parameters are used, e.g. {@code class Foo<T>}).</p>
|
||||
*
|
||||
* <p>See <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4">
|
||||
* http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4</a>
|
||||
* for a more formal definition of a type variable</p>.
|
||||
*
|
||||
* @param type a type object ({@code null} is allowed)
|
||||
* @return {@code true} if there were nested type variables; {@code false} otherwise
|
||||
*/
|
||||
public static boolean containsTypeVariable(Type type) {
|
||||
if (type == null) {
|
||||
// Trivially false
|
||||
return false;
|
||||
} else if (type instanceof TypeVariable<?>) {
|
||||
/*
|
||||
* T -> trivially true
|
||||
*/
|
||||
return true;
|
||||
} else if (type instanceof Class<?>) {
|
||||
/*
|
||||
* class Foo -> no type variable
|
||||
* class Foo<T> - has a type variable
|
||||
*
|
||||
* This also covers the case of class Foo<T> extends ... / implements ...
|
||||
* since everything on the right hand side would either include a type variable T
|
||||
* or have no type variables.
|
||||
*/
|
||||
Class<?> klass = (Class<?>)type;
|
||||
|
||||
// Empty array => class is not generic
|
||||
if (klass.getTypeParameters().length != 0) {
|
||||
return true;
|
||||
} else {
|
||||
// Does the outer class(es) contain any type variables?
|
||||
|
||||
/*
|
||||
* class Outer<T> {
|
||||
* class Inner {
|
||||
* T field;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* In this case 'Inner' has no type parameters itself, but it still has a type
|
||||
* variable as part of the type definition.
|
||||
*/
|
||||
return containsTypeVariable(klass.getDeclaringClass());
|
||||
}
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
/*
|
||||
* This is the "Foo<T1, T2, T3, ... Tn>" in the scope of a
|
||||
*
|
||||
* // no type variables here, T1-Tn are known at this definition
|
||||
* class X extends Foo<T1, T2, T3, ... Tn>
|
||||
*
|
||||
* // T1 is a type variable, T2-Tn are known at this definition
|
||||
* class X<T1> extends Foo<T1, T2, T3, ... Tn>
|
||||
*/
|
||||
ParameterizedType p = (ParameterizedType) type;
|
||||
|
||||
// This needs to be recursively checked
|
||||
for (Type arg : p.getActualTypeArguments()) {
|
||||
if (containsTypeVariable(arg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (type instanceof WildcardType) {
|
||||
WildcardType wild = (WildcardType) type;
|
||||
|
||||
/*
|
||||
* This is is the "?" inside of a
|
||||
*
|
||||
* Foo<?> --> unbounded; trivially no type variables
|
||||
* Foo<? super T> --> lower bound; does T have a type variable?
|
||||
* Foo<? extends T> --> upper bound; does T have a type variable?
|
||||
*/
|
||||
|
||||
/*
|
||||
* According to JLS 4.5.1
|
||||
* (http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.5.1):
|
||||
*
|
||||
* - More than 1 lower/upper bound is illegal
|
||||
* - Both a lower and upper bound is illegal
|
||||
*
|
||||
* However, we use this 'array OR array' approach for readability
|
||||
*/
|
||||
return containsTypeVariable(wild.getLowerBounds()) ||
|
||||
containsTypeVariable(wild.getUpperBounds());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("TypeReference<");
|
||||
toString(getType(), builder);
|
||||
builder.append(">");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static void toString(Type type, StringBuilder out) {
|
||||
if (type == null) {
|
||||
return;
|
||||
} else if (type instanceof TypeVariable<?>) {
|
||||
// T
|
||||
out.append(((TypeVariable<?>)type).getName());
|
||||
} else if (type instanceof Class<?>) {
|
||||
Class<?> klass = (Class<?>)type;
|
||||
|
||||
out.append(klass.getName());
|
||||
toString(klass.getTypeParameters(), out);
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
// "Foo<T1, T2, T3, ... Tn>"
|
||||
ParameterizedType p = (ParameterizedType) type;
|
||||
|
||||
out.append(((Class<?>)p.getRawType()).getName());
|
||||
toString(p.getActualTypeArguments(), out);
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
GenericArrayType gat = (GenericArrayType)type;
|
||||
|
||||
toString(gat.getGenericComponentType(), out);
|
||||
out.append("[]");
|
||||
} else { // WildcardType, BoundedType
|
||||
// TODO:
|
||||
out.append(type.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void toString(Type[] types, StringBuilder out) {
|
||||
if (types == null) {
|
||||
return;
|
||||
} else if (types.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
out.append("<");
|
||||
|
||||
for (int i = 0; i < types.length; ++i) {
|
||||
toString(types[i], out);
|
||||
if (i != types.length - 1) {
|
||||
out.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
out.append(">");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any of the elements in this array contained a type variable.
|
||||
*
|
||||
* <p>Empty and null arrays trivially have no type variables.</p>
|
||||
*
|
||||
* @param typeArray an array ({@code null} is ok) of types
|
||||
* @return true if any elements contained a type variable; false otherwise
|
||||
*/
|
||||
private static boolean containsTypeVariable(Type[] typeArray) {
|
||||
if (typeArray == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Type type : typeArray) {
|
||||
if (containsTypeVariable(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ package android.util;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
import android.hardware.camera2.utils.HashCodeHelpers;
|
||||
|
||||
/**
|
||||
* Immutable class for describing the range of two numeric values.
|
||||
|
||||
@@ -489,8 +489,13 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN
|
||||
|
||||
sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
|
||||
|
||||
SortedVector<String8> vendorSections = vTags->getAllSectionNames();
|
||||
size_t vendorSectionCount = vendorSections.size();
|
||||
SortedVector<String8> vendorSections;
|
||||
size_t vendorSectionCount = 0;
|
||||
|
||||
if (vTags != 0) {
|
||||
vendorSections = vTags->getAllSectionNames();
|
||||
vendorSectionCount = vendorSections.size();
|
||||
}
|
||||
|
||||
// First, find the section by the longest string match
|
||||
const char *section = NULL;
|
||||
@@ -561,7 +566,7 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN
|
||||
"Could not find tag name for key '%s')", key);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
} else if (vTags != 0) {
|
||||
// Match vendor tags (typically com.*)
|
||||
const String8 sectionName(section);
|
||||
const String8 tagName(keyTagName);
|
||||
|
||||
@@ -7,7 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target core-tests android-support-test
|
||||
|
||||
LOCAL_PACKAGE_NAME := mediaframeworktest
|
||||
|
||||
|
||||
@@ -76,4 +76,8 @@
|
||||
android:label="MediaFramework integration tests InstrumentationRunner">
|
||||
</instrumentation>
|
||||
|
||||
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.mediaframeworktest"
|
||||
android:label="media framework tests"/>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -63,6 +63,7 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
|
||||
suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
|
||||
suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
|
||||
suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
|
||||
suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
|
||||
suite.addTestSuite(CameraMetadataTest.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 com.android.mediaframeworktest.unit;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ByteArrayHelpers {
|
||||
|
||||
private static final String TAG = "ByteArrayHelpers";
|
||||
private static boolean VERBOSE = false;
|
||||
|
||||
/**
|
||||
* Convert an array of byte primitives to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* <p>This function is a pass-through; it's here only to provide overloads for
|
||||
* every single type of primitive arrays.
|
||||
*
|
||||
* @param array array of primitives
|
||||
* @return array
|
||||
*/
|
||||
public static byte[] toByteArray(byte[] array) {
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of shorts to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* @param array array of shorts
|
||||
* @return array converted into byte array using native endian order
|
||||
*/
|
||||
public static byte[] toByteArray(short[] array) {
|
||||
return toByteArray(array, Short.SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of chars to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* @param array array of chars
|
||||
* @return array converted into byte array using native endian order
|
||||
*/
|
||||
public static byte[] toByteArray(char[] array) {
|
||||
return toByteArray(array, Character.SIZE);
|
||||
}
|
||||
/**
|
||||
* Convert an array of ints to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* @param array array of ints
|
||||
* @return array converted into byte array using native endian order
|
||||
*/
|
||||
public static byte[] toByteArray(int[] array) {
|
||||
return toByteArray(array, Integer.SIZE);
|
||||
}
|
||||
/**
|
||||
* Convert an array of longs to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* @param array array of longs
|
||||
* @return array converted into byte array using native endian order
|
||||
*/
|
||||
public static byte[] toByteArray(long[] array) {
|
||||
return toByteArray(array, Long.SIZE);
|
||||
}
|
||||
/**
|
||||
* Convert an array of floats to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* @param array array of floats
|
||||
* @return array converted into byte array using native endian order
|
||||
*/
|
||||
public static byte[] toByteArray(float[] array) {
|
||||
return toByteArray(array, Float.SIZE);
|
||||
}
|
||||
/**
|
||||
* Convert an array of doubles to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* @param array array of doubles
|
||||
* @return array converted into byte array using native endian order
|
||||
*/
|
||||
public static byte[] toByteArray(double[] array) {
|
||||
return toByteArray(array, Double.SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of primitives to a {@code byte[]} using native endian order.
|
||||
*
|
||||
* <p>Arguments other than arrays are not supported. The array component must be primitive,
|
||||
* the wrapper class is not allowed (e.g. {@code int[]} is ok, but {@code Integer[]} is not.</p>
|
||||
*
|
||||
* @param array array of primitives
|
||||
* @return array converted into byte array using native endian order
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code array} was not an array of primitives
|
||||
*/
|
||||
public static <T> byte[] toByteArray(T array) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> klass = (Class<T>) array.getClass();
|
||||
|
||||
if (!klass.isArray()) {
|
||||
throw new IllegalArgumentException("array class must be an array");
|
||||
}
|
||||
|
||||
Class<?> componentClass = klass.getComponentType();
|
||||
|
||||
if (!componentClass.isPrimitive()) {
|
||||
throw new IllegalArgumentException("array's component must be a primitive");
|
||||
}
|
||||
|
||||
int sizeInBits;
|
||||
if (klass == int.class) {
|
||||
sizeInBits = Integer.SIZE;
|
||||
} else if (klass == float.class) {
|
||||
sizeInBits = Float.SIZE;
|
||||
} else if (klass == double.class) {
|
||||
sizeInBits = Double.SIZE;
|
||||
} else if (klass == short.class) {
|
||||
sizeInBits = Short.SIZE;
|
||||
} else if (klass == char.class) {
|
||||
sizeInBits = Character.SIZE;
|
||||
} else if (klass == long.class) {
|
||||
sizeInBits = Long.SIZE;
|
||||
} else if (klass == byte.class) {
|
||||
sizeInBits = Byte.SIZE;
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
return toByteArray(array, sizeInBits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a variadic list of {@code Number}s into a byte array using native endian order.
|
||||
*
|
||||
* <p>Each {@link Number} must be an instance of a primitive wrapper class
|
||||
* (e.g. {@link Integer} is OK, since it wraps {@code int}, but {@code BigInteger} is not.</p>
|
||||
*
|
||||
* @param numbers variadic list of numeric values
|
||||
* @return array converted into byte array using native endian order
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code numbers} contained a class that wasn't a primitive wrapper
|
||||
*/
|
||||
public static byte[] toByteArray(Number... numbers) {
|
||||
if (numbers.length == 0) {
|
||||
throw new IllegalArgumentException("too few numbers");
|
||||
}
|
||||
|
||||
if (VERBOSE) Log.v(TAG, "toByteArray - input: " + Arrays.toString(numbers));
|
||||
|
||||
// Have a large enough capacity to fit in every number as a double
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(numbers.length * (Double.SIZE / Byte.SIZE))
|
||||
.order(ByteOrder.nativeOrder());
|
||||
|
||||
for (int i = 0; i < numbers.length; ++i) {
|
||||
Number value = numbers[i];
|
||||
Class<? extends Number> klass = value.getClass();
|
||||
|
||||
if (VERBOSE) Log.v(TAG, "toByteArray - number " + i + ", class " + klass);
|
||||
|
||||
if (klass == Integer.class) {
|
||||
byteBuffer.putInt((Integer)value);
|
||||
} else if (klass == Float.class) {
|
||||
byteBuffer.putFloat((Float)value);
|
||||
} else if (klass == Double.class) {
|
||||
byteBuffer.putDouble((Double)value);
|
||||
} else if (klass == Short.class) {
|
||||
byteBuffer.putShort((Short)value);
|
||||
} else if (klass == Long.class) {
|
||||
byteBuffer.putLong((Long)value);
|
||||
} else if (klass == Byte.class) {
|
||||
byteBuffer.put((Byte)value);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"number class invalid; must be wrapper around primitive class");
|
||||
}
|
||||
}
|
||||
|
||||
if (VERBOSE) Log.v(TAG, "toByteArray - end of loop");
|
||||
|
||||
// Each number written is at least 1 byte, so the position should be at least length
|
||||
if (numbers.length != 0 && byteBuffer.position() < numbers.length) {
|
||||
throw new AssertionError(String.format(
|
||||
"Had %d numbers, but byte buffer position was only %d",
|
||||
numbers.length, byteBuffer.position()));
|
||||
}
|
||||
|
||||
byteBuffer.flip();
|
||||
|
||||
byte[] bytes = new byte[byteBuffer.limit()];
|
||||
byteBuffer.get(bytes);
|
||||
|
||||
if (VERBOSE) Log.v(TAG, "toByteArray - output: " + Arrays.toString(bytes));
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static <T> byte[] toByteArray(T array, int sizeOfTBits) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> klass = (Class<T>) array.getClass();
|
||||
|
||||
if (!klass.isArray()) {
|
||||
throw new IllegalArgumentException("array class must be an array");
|
||||
}
|
||||
|
||||
int sizeOfT = sizeOfTBits / Byte.SIZE;
|
||||
int byteLength = Array.getLength(array) * sizeOfT;
|
||||
|
||||
if (klass == byte[].class) {
|
||||
// Always return a copy
|
||||
return Arrays.copyOf((byte[])array, byteLength);
|
||||
}
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(byteLength).order(ByteOrder.nativeOrder());
|
||||
|
||||
if (klass == int[].class) {
|
||||
byteBuffer.asIntBuffer().put((int[])array);
|
||||
} else if (klass == float[].class) {
|
||||
byteBuffer.asFloatBuffer().put((float[])array);
|
||||
} else if (klass == double[].class) {
|
||||
byteBuffer.asDoubleBuffer().put((double[])array);
|
||||
} else if (klass == short[].class) {
|
||||
byteBuffer.asShortBuffer().put((short[])array);
|
||||
} else if (klass == char[].class) {
|
||||
byteBuffer.asCharBuffer().put((char[])array);
|
||||
} else if (klass == long[].class) {
|
||||
byteBuffer.asLongBuffer().put((long[])array);
|
||||
} else {
|
||||
throw new IllegalArgumentException("array class invalid; must be a primitive array");
|
||||
}
|
||||
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
private ByteArrayHelpers() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,30 @@
|
||||
|
||||
package com.android.mediaframeworktest.unit;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Range;
|
||||
import android.util.SizeF;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CaptureResult;
|
||||
import android.hardware.camera2.ColorSpaceTransform;
|
||||
import android.hardware.camera2.Face;
|
||||
import android.hardware.camera2.MeteringRectangle;
|
||||
import android.hardware.camera2.Rational;
|
||||
import android.hardware.camera2.ReprocessFormatsMap;
|
||||
import android.hardware.camera2.RggbChannelVector;
|
||||
import android.hardware.camera2.Size;
|
||||
import android.hardware.camera2.StreamConfiguration;
|
||||
import android.hardware.camera2.StreamConfigurationDuration;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import static android.hardware.camera2.impl.CameraMetadataNative.*;
|
||||
import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -43,7 +55,6 @@ import java.nio.ByteOrder;
|
||||
public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
|
||||
CameraMetadataNative mMetadata;
|
||||
Parcel mParcel;
|
||||
|
||||
// Sections
|
||||
static final int ANDROID_COLOR_CORRECTION = 0;
|
||||
@@ -64,15 +75,11 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
@Override
|
||||
public void setUp() {
|
||||
mMetadata = new CameraMetadataNative();
|
||||
mParcel = Parcel.obtain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
mMetadata = null;
|
||||
|
||||
mParcel.recycle();
|
||||
mParcel = null;
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@@ -130,10 +137,14 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
|
||||
@SmallTest
|
||||
public void testGetTypeFromTag() {
|
||||
assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
|
||||
assertEquals(TYPE_RATIONAL, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
|
||||
assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
|
||||
assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
|
||||
assertEquals(TYPE_BYTE,
|
||||
CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
|
||||
assertEquals(TYPE_RATIONAL,
|
||||
CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
|
||||
assertEquals(TYPE_FLOAT,
|
||||
CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
|
||||
assertEquals(TYPE_BYTE,
|
||||
CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
|
||||
assertEquals(TYPE_INT32,
|
||||
CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
|
||||
|
||||
@@ -215,35 +226,163 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
assertEquals(1, mMetadata.getEntryCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an array into a string with the {@code badIndex} highlighted with {@code **}.
|
||||
*
|
||||
* <p>Numbers are printed as hexadecimal values.</p>
|
||||
*
|
||||
* <p>Example: {@code "[hello, **world**]"} for a {@code string[]},
|
||||
* or a {@code "[**0xFF**, 0xFF]"} for a {@code int[]}.</p>
|
||||
*/
|
||||
private static <T> String formatArray(T array, int badIndex) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("[");
|
||||
|
||||
int len = Array.getLength(array);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
|
||||
Object elem = Array.get(array, i);
|
||||
|
||||
if (i == badIndex) {
|
||||
builder.append("**");
|
||||
}
|
||||
|
||||
if (elem instanceof Number) {
|
||||
builder.append(String.format("%x", elem));
|
||||
} else {
|
||||
builder.append(elem);
|
||||
}
|
||||
|
||||
if (i == badIndex) {
|
||||
builder.append("**");
|
||||
}
|
||||
|
||||
if (i != len - 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static <T> void assertArrayEquals(T expected, T actual) {
|
||||
assertEquals(Array.getLength(expected), Array.getLength(actual));
|
||||
if (!expected.getClass().isArray() || !actual.getClass().isArray()) {
|
||||
throw new IllegalArgumentException("expected, actual must both be arrays");
|
||||
}
|
||||
|
||||
assertEquals("Array lengths must be equal",
|
||||
Array.getLength(expected), Array.getLength(actual));
|
||||
|
||||
int len = Array.getLength(expected);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
assertEquals(Array.get(expected, i), Array.get(actual, i));
|
||||
|
||||
Object expectedElement = Array.get(expected, i);
|
||||
Object actualElement = Array.get(actual, i);
|
||||
|
||||
if (!expectedElement.equals(actualElement)) {
|
||||
fail(String.format(
|
||||
"element %d in array was not equal (expected %s, actual %s). "
|
||||
+ "Arrays were: (expected %s, actual %s).",
|
||||
i, expectedElement, actualElement,
|
||||
formatArray(expected, i),
|
||||
formatArray(actual, i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
|
||||
assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray());
|
||||
|
||||
Key<T> key = new Key<T>(keyStr, type);
|
||||
private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected,
|
||||
boolean reuse) {
|
||||
Key<T> key = new Key<T>(keyStr, typeToken);
|
||||
assertNull(mMetadata.get(key));
|
||||
mMetadata.set(key, null);
|
||||
assertNull(mMetadata.get(key));
|
||||
mMetadata.set(key, value);
|
||||
mMetadata.set(key, expected);
|
||||
|
||||
T actual = mMetadata.get(key);
|
||||
assertEquals(value, actual);
|
||||
|
||||
if (typeToken.getRawType().isArray()) {
|
||||
assertArrayEquals(expected, actual);
|
||||
} else {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
if (reuse) {
|
||||
// reset the key incase we want to use it again
|
||||
mMetadata.set(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
|
||||
assertTrue(type.isArray());
|
||||
private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected) {
|
||||
checkKeyGetAndSet(keyStr, typeToken, expected, /*reuse*/false);
|
||||
}
|
||||
|
||||
Key<T> key = new Key<T>(keyStr, type);
|
||||
private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T expected) {
|
||||
checkKeyGetAndSet(keyStr, TypeReference.createSpecializedTypeReference(type), expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the data survives a marshal/unmarshal round-trip;
|
||||
* it must also be equal to the {@code expectedNative} byte array.
|
||||
*
|
||||
* <p>As a side-effect, the metadata value corresponding to the key is now set to
|
||||
* {@code expected}.</p>
|
||||
*
|
||||
* @return key created with {@code keyName} and {@code T}
|
||||
*/
|
||||
private <T> Key<T> checkKeyMarshal(String keyName, TypeReference<T> typeReference,
|
||||
T expected, byte[] expectedNative) {
|
||||
Key<T> key = new Key<T>(keyName, typeReference);
|
||||
|
||||
mMetadata.set(key, null);
|
||||
assertNull(mMetadata.get(key));
|
||||
mMetadata.set(key, value);
|
||||
assertArrayEquals(value, mMetadata.get(key));
|
||||
|
||||
// Write managed value -> make sure native bytes are what we expect
|
||||
mMetadata.set(key, expected);
|
||||
|
||||
byte[] actualValues = mMetadata.readValues(key.getTag());
|
||||
assertArrayEquals(expectedNative, actualValues);
|
||||
|
||||
// Write managed value -> make sure read-out managed value is what we expect
|
||||
T actual = mMetadata.get(key);
|
||||
|
||||
if (typeReference.getRawType().isArray()) {
|
||||
assertArrayEquals(expected, actual);
|
||||
} else {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
// Write native bytes -> make sure read-out managed value is what we expect
|
||||
mMetadata.writeValues(key.getTag(), expectedNative);
|
||||
actual = mMetadata.get(key);
|
||||
|
||||
if (typeReference.getRawType().isArray()) {
|
||||
assertArrayEquals(expected, actual);
|
||||
} else {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the data survives a marshal/unmarshal round-trip;
|
||||
* it must also be equal to the {@code expectedNative} byte array.
|
||||
*
|
||||
* <p>As a side-effect,
|
||||
* the metadata value corresponding to the key is now set to {@code expected}.</p>
|
||||
*
|
||||
* @return key created with {@code keyName} and {@code T}
|
||||
*/
|
||||
private <T> Key<T> checkKeyMarshal(String keyName, T expected, byte[] expectedNative) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> expectedClass = (Class<T>) expected.getClass();
|
||||
return checkKeyMarshal(keyName,
|
||||
TypeReference.createSpecializedTypeReference(expectedClass),
|
||||
expected,
|
||||
expectedNative);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@@ -280,36 +419,36 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
@SmallTest
|
||||
public void testReadWritePrimitiveArray() {
|
||||
// int32 (n)
|
||||
checkKeyGetAndSetArray("android.sensor.info.sensitivityRange", int[].class,
|
||||
checkKeyGetAndSet("android.sensor.info.sensitivityRange", int[].class,
|
||||
new int[] {
|
||||
0xC0FFEE, 0xDEADF00D
|
||||
});
|
||||
|
||||
// byte (n)
|
||||
checkKeyGetAndSetArray("android.statistics.faceScores", byte[].class, new byte[] {
|
||||
checkKeyGetAndSet("android.statistics.faceScores", byte[].class, new byte[] {
|
||||
1, 2, 3, 4
|
||||
});
|
||||
|
||||
// int64 (n)
|
||||
checkKeyGetAndSetArray("android.scaler.availableProcessedMinDurations", long[].class,
|
||||
checkKeyGetAndSet("android.scaler.availableProcessedMinDurations", long[].class,
|
||||
new long[] {
|
||||
0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
|
||||
});
|
||||
|
||||
// float (n)
|
||||
checkKeyGetAndSetArray("android.lens.info.availableApertures", float[].class,
|
||||
checkKeyGetAndSet("android.lens.info.availableApertures", float[].class,
|
||||
new float[] {
|
||||
Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
|
||||
});
|
||||
|
||||
// double (n) -- in particular double x 3
|
||||
checkKeyGetAndSetArray("android.jpeg.gpsCoordinates", double[].class,
|
||||
checkKeyGetAndSet("android.jpeg.gpsCoordinates", double[].class,
|
||||
new double[] {
|
||||
Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
|
||||
});
|
||||
|
||||
// rational (n) -- in particular rational x 9
|
||||
checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
|
||||
checkKeyGetAndSet("android.sensor.calibrationTransform1", Rational[].class,
|
||||
new Rational[] {
|
||||
new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
|
||||
new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
|
||||
@@ -321,13 +460,12 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
*/
|
||||
|
||||
// bool (n) -- with TYPE_BYTE
|
||||
checkKeyGetAndSetArray("android.control.aeLock", boolean[].class, new boolean[] {
|
||||
checkKeyGetAndSet("android.control.aeLock", boolean[].class, new boolean[] {
|
||||
true, false, true
|
||||
});
|
||||
|
||||
|
||||
// integer (n) -- with TYPE_BYTE
|
||||
checkKeyGetAndSetArray("android.control.aeAvailableModes", int[].class, new int[] {
|
||||
checkKeyGetAndSet("android.control.aeAvailableModes", int[].class, new int[] {
|
||||
1, 2, 3, 4
|
||||
});
|
||||
}
|
||||
@@ -345,7 +483,6 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
AUTO
|
||||
}
|
||||
|
||||
// TODO: special values for the enum.
|
||||
private enum AvailableFormat {
|
||||
RAW_SENSOR,
|
||||
YV12,
|
||||
@@ -366,7 +503,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
AeAntibandingMode.AUTO);
|
||||
|
||||
// byte (n)
|
||||
checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
|
||||
checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
|
||||
AeAntibandingMode[].class, new AeAntibandingMode[] {
|
||||
AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
|
||||
AeAntibandingMode.AUTO
|
||||
@@ -376,7 +513,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
* Stranger cases that don't use byte enums
|
||||
*/
|
||||
// int (n)
|
||||
checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
|
||||
checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
|
||||
new AvailableFormat[] {
|
||||
AvailableFormat.RAW_SENSOR,
|
||||
AvailableFormat.YV12,
|
||||
@@ -389,7 +526,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteEnumWithCustomValues() {
|
||||
CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
|
||||
MarshalQueryableEnum.registerEnumValues(AeAntibandingMode.class, new int[] {
|
||||
0,
|
||||
10,
|
||||
20,
|
||||
@@ -401,15 +538,12 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
AeAntibandingMode.AUTO);
|
||||
|
||||
// byte (n)
|
||||
checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
|
||||
checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
|
||||
AeAntibandingMode[].class, new AeAntibandingMode[] {
|
||||
AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
|
||||
AeAntibandingMode.AUTO
|
||||
});
|
||||
|
||||
Key<AeAntibandingMode[]> aeAntibandingModeKey =
|
||||
new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
|
||||
AeAntibandingMode[].class);
|
||||
byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
|
||||
.getTag("android.control.aeAvailableAntibandingModes"));
|
||||
byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
|
||||
@@ -420,7 +554,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
* Stranger cases that don't use byte enums
|
||||
*/
|
||||
// int (n)
|
||||
CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
|
||||
MarshalQueryableEnum.registerEnumValues(AvailableFormat.class, new int[] {
|
||||
0x20,
|
||||
0x32315659,
|
||||
0x11,
|
||||
@@ -429,7 +563,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
0x21,
|
||||
});
|
||||
|
||||
checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
|
||||
checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
|
||||
new AvailableFormat[] {
|
||||
AvailableFormat.RAW_SENSOR,
|
||||
AvailableFormat.YV12,
|
||||
@@ -466,7 +600,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
|
||||
|
||||
// int32 x 2 x n
|
||||
checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] {
|
||||
checkKeyGetAndSet("android.scaler.availableJpegSizes", Size[].class, new Size[] {
|
||||
new Size(123, 456),
|
||||
new Size(0xDEAD, 0xF00D),
|
||||
new Size(0xF00, 0xB00)
|
||||
@@ -474,16 +608,217 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteRectangle() {
|
||||
public void testReadWriteRggbChannelVector() {
|
||||
// int32 x n
|
||||
checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024));
|
||||
checkKeyMarshal("android.colorCorrection.gains",
|
||||
new RggbChannelVector(1.0f, 2.1f, 3.2f, 4.5f),
|
||||
toByteArray(1.0f, 2.1f, 3.2f, 4.5f));
|
||||
|
||||
// int32 x 2 x n [pretend; actual is not array]
|
||||
checkKeyMarshal("android.colorCorrection.gains",
|
||||
new RggbChannelVector[] {
|
||||
new RggbChannelVector(1.0f, 2.0f, 3.0f, 4.0f),
|
||||
new RggbChannelVector(9.0f, 8.0f, 7.0f, 6.0f),
|
||||
new RggbChannelVector(1.3f, 5.5f, 2.4f, 6.7f),
|
||||
}, toByteArray(
|
||||
1.0f, 2.0f, 3.0f, 4.0f,
|
||||
9.0f, 8.0f, 7.0f, 6.0f,
|
||||
1.3f, 5.5f, 2.4f, 6.7f
|
||||
));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteSizeF() {
|
||||
// int32 x n
|
||||
checkKeyMarshal("android.sensor.info.physicalSize",
|
||||
new SizeF(123f, 456f),
|
||||
toByteArray(123f, 456f));
|
||||
|
||||
// int32 x 2 x n
|
||||
checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] {
|
||||
checkKeyMarshal("android.sensor.info.physicalSize",
|
||||
new SizeF[] {
|
||||
new SizeF(123f, 456f),
|
||||
new SizeF(1.234f, 4.567f),
|
||||
new SizeF(999.0f, 555.0f)
|
||||
},
|
||||
toByteArray(
|
||||
123f, 456f,
|
||||
1.234f, 4.567f,
|
||||
999.0f, 555.0f)
|
||||
);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteRectangle() {
|
||||
// int32 x n
|
||||
checkKeyMarshal("android.scaler.cropRegion",
|
||||
// x1, y1, x2, y2
|
||||
new Rect(10, 11, 1280, 1024),
|
||||
// x, y, width, height
|
||||
toByteArray(10, 11, 1280 - 10, 1024 - 11));
|
||||
|
||||
// int32 x 2 x n [actually not array, but we pretend it is]
|
||||
checkKeyMarshal("android.scaler.cropRegion", new Rect[] {
|
||||
new Rect(110, 111, 11280, 11024),
|
||||
new Rect(210, 111, 21280, 21024),
|
||||
new Rect(310, 111, 31280, 31024)
|
||||
});
|
||||
}, toByteArray(
|
||||
110, 111, 11280 - 110, 11024 - 111,
|
||||
210, 111, 21280 - 210, 21024 - 111,
|
||||
310, 111, 31280 - 310, 31024 - 111
|
||||
));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteMeteringRectangle() {
|
||||
// int32 x 5 x area_count [but we pretend it's a single element]
|
||||
checkKeyMarshal("android.control.aeRegions",
|
||||
new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5),
|
||||
/* xmin, ymin, xmax, ymax, weight */
|
||||
toByteArray(1, 2, 1 + 100, 2 + 200, 5));
|
||||
|
||||
// int32 x 5 x area_count
|
||||
checkKeyMarshal("android.control.afRegions",
|
||||
new MeteringRectangle[] {
|
||||
new MeteringRectangle(/*x*/5, /*y*/6, /*width*/123, /*height*/456, /*weight*/7),
|
||||
new MeteringRectangle(/*x*/7, /*y*/8, /*width*/456, /*height*/999, /*weight*/6),
|
||||
new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5)
|
||||
},
|
||||
toByteArray(
|
||||
5, 6, 5 + 123, 6 + 456, 7,
|
||||
7, 8, 7 + 456, 8 + 999, 6,
|
||||
1, 2, 1 + 100, 2 + 200, 5
|
||||
));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteColorSpaceTransform() {
|
||||
// rational x 3 x 3
|
||||
checkKeyMarshal("android.colorCorrection.transform",
|
||||
new ColorSpaceTransform(new Rational[] {
|
||||
new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
|
||||
new Rational(7, 8), new Rational(8, 9), new Rational(10, 11),
|
||||
new Rational(1, 5), new Rational(2, 8), new Rational(3, 9),
|
||||
}),
|
||||
toByteArray(
|
||||
1, 2, 3, 4, 5, 6,
|
||||
7, 8, 8, 9, 10, 11,
|
||||
1, 5, 2, 8, 3, 9));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWritePoint() {
|
||||
// int32 x 2 [actually 'x n' but pretend it's a single value for now]
|
||||
checkKeyMarshal("android.statistics.hotPixelMap",
|
||||
new Point(1, 2),
|
||||
toByteArray(1, 2));
|
||||
|
||||
// int32 x 2 x samples
|
||||
checkKeyMarshal("android.statistics.hotPixelMap",
|
||||
new Point[] {
|
||||
new Point(1, 2),
|
||||
new Point(3, 4),
|
||||
new Point(5, 6),
|
||||
new Point(7, 8),
|
||||
},
|
||||
toByteArray(
|
||||
1, 2,
|
||||
3, 4,
|
||||
5, 6,
|
||||
7, 8)
|
||||
);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWritePointF() {
|
||||
// float x 2 [actually 'x samples' but pretend it's a single value for now]
|
||||
checkKeyMarshal(
|
||||
"android.sensor.profileToneCurve",
|
||||
new PointF(1.0f, 2.0f),
|
||||
toByteArray(1.0f, 2.0f));
|
||||
|
||||
// float x 2 x samples
|
||||
checkKeyMarshal("android.sensor.profileToneCurve",
|
||||
new PointF[] {
|
||||
new PointF(1.0f, 2.0f),
|
||||
new PointF(3.0f, 4.0f),
|
||||
new PointF(5.0f, 6.0f),
|
||||
new PointF(7.0f, 8.0f),
|
||||
},
|
||||
toByteArray(
|
||||
1.0f, 2.0f,
|
||||
3.0f, 4.0f,
|
||||
5.0f, 6.0f,
|
||||
7.0f, 8.0f));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteRange() {
|
||||
// int32 x 2
|
||||
checkKeyMarshal("android.control.aeTargetFpsRange",
|
||||
new TypeReference<Range<Integer>>() {{ }},
|
||||
Range.create(123, 456),
|
||||
toByteArray(123, 456));
|
||||
|
||||
// int64 x 2
|
||||
checkKeyMarshal("android.sensor.info.exposureTimeRange",
|
||||
new TypeReference<Range<Long>>() {{ }},
|
||||
Range.create(123L, 456L),
|
||||
toByteArray(123L, 456L));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteStreamConfiguration() {
|
||||
// int32 x 4 x n
|
||||
checkKeyMarshal("android.scaler.availableStreamConfigurations",
|
||||
new StreamConfiguration[] {
|
||||
new StreamConfiguration(ImageFormat.YUV_420_888, 640, 480, /*input*/false),
|
||||
new StreamConfiguration(ImageFormat.RGB_565, 320, 240, /*input*/true),
|
||||
},
|
||||
toByteArray(
|
||||
ImageFormat.YUV_420_888, 640, 480, /*input*/0,
|
||||
ImageFormat.RGB_565, 320, 240, /*input*/1)
|
||||
);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteStreamConfigurationDuration() {
|
||||
// Avoid sign extending ints when converting to a long
|
||||
final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
|
||||
|
||||
// int64 x 4 x n
|
||||
checkKeyMarshal("android.scaler.availableMinFrameDurations",
|
||||
new StreamConfigurationDuration[] {
|
||||
new StreamConfigurationDuration(
|
||||
ImageFormat.YUV_420_888, 640, 480, /*duration*/123L),
|
||||
new StreamConfigurationDuration(
|
||||
ImageFormat.RGB_565, 320, 240, /*duration*/345L),
|
||||
},
|
||||
toByteArray(
|
||||
ImageFormat.YUV_420_888 & MASK_UNSIGNED_INT, 640L, 480L, /*duration*/123L,
|
||||
ImageFormat.RGB_565 & MASK_UNSIGNED_INT, 320L, 240L, /*duration*/345L)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteReprocessFormatsMap() {
|
||||
|
||||
final int RAW_OPAQUE = 0x24;
|
||||
final int RAW16 = ImageFormat.RAW_SENSOR;
|
||||
final int YUV_420_888 = ImageFormat.YUV_420_888;
|
||||
final int BLOB = 0x21;
|
||||
|
||||
int[] contents = new int[] {
|
||||
RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
|
||||
RAW16, 2, YUV_420_888, BLOB,
|
||||
};
|
||||
|
||||
// int32 x n
|
||||
checkKeyMarshal("android.scaler.availableInputOutputFormatsMap",
|
||||
new ReprocessFormatsMap(contents),
|
||||
toByteArray(contents)
|
||||
);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@@ -525,10 +860,6 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
assertArrayEquals(gpsBytes, actualBytes2);
|
||||
}
|
||||
|
||||
<T> void compareGeneric(T expected, T actual) {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testReadWriteOverride() {
|
||||
//
|
||||
@@ -691,7 +1022,7 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
*/
|
||||
private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues,
|
||||
T readValues, int tag) {
|
||||
Class<T> type = key.getType();
|
||||
Class<?> type = writeValues.getClass();
|
||||
if (!type.isArray()) {
|
||||
throw new IllegalArgumentException("This function expects an key with array type");
|
||||
} else if (type != int[].class && type != long[].class) {
|
||||
@@ -737,4 +1068,20 @@ public class CameraMetadataTest extends junit.framework.TestCase {
|
||||
assertNotNull(key.getName() + " result shouldn't be null", result);
|
||||
assertArrayEquals(writeValues, result);
|
||||
}
|
||||
|
||||
// TODO: move somewhere else
|
||||
@SmallTest
|
||||
public void testToByteArray() {
|
||||
assertArrayEquals(new byte[] { 5, 0, 0, 0, 6, 0, 0, 0 },
|
||||
toByteArray(5, 6));
|
||||
assertArrayEquals(new byte[] { 5, 0, 6, 0, },
|
||||
toByteArray((short)5, (short)6));
|
||||
assertArrayEquals(new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
|
||||
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,},
|
||||
toByteArray(~0, ~0));
|
||||
|
||||
assertArrayEquals(new byte[] { (byte)0xAB, (byte)0xFF, 0, 0,
|
||||
0x0D, (byte)0xF0, (byte)0xAD, (byte)0xDE },
|
||||
toByteArray(0xFFAB, 0xDEADF00D));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 com.android.mediaframeworktest.unit;
|
||||
|
||||
import static android.hardware.camera2.utils.TypeReference.*;
|
||||
|
||||
import android.hardware.camera2.utils.TypeReference;
|
||||
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class CameraUtilsTypeReferenceTest extends junit.framework.TestCase {
|
||||
private static final String TAG = CameraUtilsTypeReferenceTest.class.getSimpleName();
|
||||
private static final boolean VERBOSE = false;
|
||||
|
||||
private class RegularClass {}
|
||||
private class SubClass extends RegularClass {}
|
||||
|
||||
private class GenericClass<T> {}
|
||||
private class SubGenericClass<T> extends GenericClass<T> {}
|
||||
|
||||
private class SpecificClass extends GenericClass<Integer> {}
|
||||
|
||||
private interface RegularInterface {}
|
||||
private interface GenericInterface<T> {}
|
||||
private interface GenericInterface2<T> {}
|
||||
|
||||
private class ImplementsRegularInterface implements RegularInterface {}
|
||||
private class ImplementsGenericInterface<T> implements GenericInterface<T> {}
|
||||
private class Implements2GenericInterface<T>
|
||||
implements GenericInterface<Integer>, GenericInterface2<T> {}
|
||||
|
||||
private class GenericOuterClass<T> {
|
||||
class GenericInnerClass {
|
||||
@SuppressWarnings("unused")
|
||||
T field;
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertContainsTypeVariable(Type type) {
|
||||
assertTrue(type.toString() + " was expected to have a type variable, but it didn't",
|
||||
containsTypeVariable(type));
|
||||
}
|
||||
|
||||
private static void assertLacksTypeVariable(Type type) {
|
||||
assertFalse(type.toString() + " was expected to *not* have a type variable, but it did",
|
||||
containsTypeVariable(type));
|
||||
}
|
||||
|
||||
/*
|
||||
* Only test classes and interfaces. Other types are not tested (e.g. fields, methods, etc).
|
||||
*/
|
||||
|
||||
@SmallTest
|
||||
public void testLacksTypeVariables() {
|
||||
assertLacksTypeVariable(RegularClass.class);
|
||||
assertLacksTypeVariable(SubClass.class);
|
||||
assertLacksTypeVariable(SpecificClass.class);
|
||||
|
||||
assertLacksTypeVariable(RegularInterface.class);
|
||||
assertLacksTypeVariable(ImplementsRegularInterface.class);
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testContainsTypeVariables() {
|
||||
assertContainsTypeVariable(GenericClass.class);
|
||||
assertContainsTypeVariable(SubGenericClass.class);
|
||||
|
||||
assertContainsTypeVariable(GenericInterface.class);
|
||||
assertContainsTypeVariable(ImplementsGenericInterface.class);
|
||||
assertContainsTypeVariable(Implements2GenericInterface.class);
|
||||
|
||||
assertContainsTypeVariable(GenericOuterClass.class);
|
||||
assertContainsTypeVariable(GenericOuterClass.GenericInnerClass.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should always throw an IllegalArgumentException since the
|
||||
* type reference to {@code T} will contain a type variable (also {@code T}).
|
||||
*
|
||||
* @throws IllegalArgumentException unconditionally
|
||||
*/
|
||||
private static <T> TypeReference<T> createTypeRefWithTypeVar() {
|
||||
return new TypeReference<T>() {{ }};
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testTypeReferences() {
|
||||
TypeReference<Integer> typeRefInt = new TypeReference<Integer>() {{ }};
|
||||
TypeReference<Integer> typeRefInt2 = new TypeReference<Integer>() {{ }};
|
||||
|
||||
assertEquals(typeRefInt, typeRefInt2);
|
||||
assertEquals("The type ref's captured type should be the Integer class",
|
||||
Integer.class, typeRefInt.getType());
|
||||
|
||||
TypeReference<Float> typeRefFloat = new TypeReference<Float>() {{ }};
|
||||
assertFalse("Integer/Float type references must not be equal",
|
||||
typeRefInt.equals(typeRefFloat));
|
||||
assertEquals("The type ref's captured type should be the Float class",
|
||||
Float.class, typeRefFloat.getType());
|
||||
|
||||
try {
|
||||
TypeReference<Integer> typeRefTypeVar = createTypeRefWithTypeVar();
|
||||
fail("Expected a type reference with type variables to fail");
|
||||
// Unreachable. Make the warning about an unused variable go away.
|
||||
assertFalse(typeRefTypeVar.equals(typeRefInt));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// OK. Expected behavior
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the raw type against rawClass
|
||||
private static <T> void assertRawTypeEquals(TypeReference<T> typeRef, Class<?> rawClass) {
|
||||
assertEquals("Expected the raw type from " + typeRef + " to match the class " + rawClass,
|
||||
rawClass, typeRef.getRawType());
|
||||
}
|
||||
|
||||
// Compare the normal type against the klass
|
||||
private static <T> void assertTypeReferenceEquals(TypeReference<T> typeRef, Class<?> klass) {
|
||||
assertEquals("Expected the type from " + typeRef + " to match the class " + klass,
|
||||
klass, typeRef.getType());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testRawTypes() {
|
||||
TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
|
||||
assertRawTypeEquals(intToken, Integer.class);
|
||||
|
||||
TypeReference<List<Integer>> listToken = new TypeReference<List<Integer>>() {{ }};
|
||||
assertRawTypeEquals(listToken, List.class);
|
||||
|
||||
TypeReference<List<List<Integer>>> listListToken =
|
||||
new TypeReference<List<List<Integer>>>() {{ }};
|
||||
assertRawTypeEquals(listListToken, List.class);
|
||||
|
||||
TypeReference<int[]> intArrayToken = new TypeReference<int[]>() {{ }};
|
||||
assertRawTypeEquals(intArrayToken, int[].class);
|
||||
|
||||
TypeReference<Integer[]> integerArrayToken = new TypeReference<Integer[]>() {{ }};
|
||||
assertRawTypeEquals(integerArrayToken, Integer[].class);
|
||||
|
||||
TypeReference<List<Integer>[]> listArrayToken = new TypeReference<List<Integer>[]>() {{ }};
|
||||
assertRawTypeEquals(listArrayToken, List[].class);
|
||||
}
|
||||
|
||||
private class IntTokenOne extends TypeReference<Integer> {}
|
||||
private class IntTokenTwo extends TypeReference<Integer> {}
|
||||
|
||||
private class IntArrayToken1 extends TypeReference<Integer[]> {}
|
||||
private class IntArrayToken2 extends TypeReference<Integer[]> {}
|
||||
|
||||
private class IntListToken1 extends TypeReference<List<Integer>> {}
|
||||
private class IntListToken2 extends TypeReference<List<Integer>> {}
|
||||
|
||||
private class IntListArrayToken1 extends TypeReference<List<Integer>[]> {}
|
||||
private class IntListArrayToken2 extends TypeReference<List<Integer>[]> {}
|
||||
|
||||
|
||||
// FIXME: Equality will fail: b/14590652
|
||||
@SmallTest
|
||||
public void testEquals() {
|
||||
// Not an array. component type should be null.
|
||||
TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
|
||||
assertEquals(intToken, intToken);
|
||||
assertEquals(intToken, new TypeReference<Integer>() {{ }});
|
||||
|
||||
assertEquals(intToken, new IntTokenOne());
|
||||
assertEquals(intToken, new IntTokenTwo());
|
||||
assertEquals(new IntTokenOne(), new IntTokenTwo());
|
||||
|
||||
assertEquals(new IntArrayToken1(), new IntArrayToken2());
|
||||
assertEquals(new IntListToken1(), new IntListToken2());
|
||||
assertEquals(new IntListArrayToken1(), new IntListArrayToken2());
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testComponentType() {
|
||||
// Not an array. component type should be null.
|
||||
TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
|
||||
assertNull(intToken.getComponentType());
|
||||
|
||||
TypeReference<List<Integer>> listToken = new TypeReference<List<Integer>>() {{ }};
|
||||
assertNull(listToken.getComponentType());
|
||||
|
||||
TypeReference<List<List<Integer>>> listListToken =
|
||||
new TypeReference<List<List<Integer>>>() {{ }};
|
||||
assertNull(listListToken.getComponentType());
|
||||
|
||||
// Check arrays. Component types should be what we expect.
|
||||
TypeReference<int[]> intArrayToken = new TypeReference<int[]>() {{ }};
|
||||
assertTypeReferenceEquals(intArrayToken.getComponentType(), int.class);
|
||||
|
||||
TypeReference<Integer[]> integerArrayToken = new TypeReference<Integer[]>() {{ }};
|
||||
assertTypeReferenceEquals(integerArrayToken.getComponentType(), Integer.class);
|
||||
|
||||
assertEquals(new IntArrayToken1().getComponentType(),
|
||||
new IntArrayToken2().getComponentType());
|
||||
|
||||
assertEquals(new IntListArrayToken1().getComponentType(),
|
||||
new IntListArrayToken2().getComponentType());
|
||||
|
||||
// FIXME: Equality will fail: b/14590652
|
||||
TypeReference<List<Integer>[]> listArrayToken = new TypeReference<List<Integer>[]>() {{ }};
|
||||
assertEquals(listToken, listArrayToken.getComponentType());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user