/*
* 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.impl.CameraMetadataNative;
import android.hardware.camera2.marshal.Marshaler;
import android.hardware.camera2.marshal.MarshalQueryable;
import android.hardware.camera2.utils.TypeReference;
import android.util.Rational;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
import static android.hardware.camera2.marshal.MarshalHelpers.*;
import java.nio.ByteBuffer;
/**
* Marshal/unmarshal built-in primitive types to and from a {@link ByteBuffer}.
*
*
The following list of type marshaling is supported:
*
* - byte <-> TYPE_BYTE
*
- int <-> TYPE_INT32
*
- long <-> TYPE_INT64
*
- float <-> TYPE_FLOAT
*
- double <-> TYPE_DOUBLE
*
- Rational <-> TYPE_RATIONAL
*
*
*
* 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}).
*
* Each managed type 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.
*/
public final class MarshalQueryablePrimitive implements MarshalQueryable {
private class MarshalerPrimitive extends Marshaler {
/** Always the wrapped class variant of the primitive class for {@code T} */
private final Class mClass;
@SuppressWarnings("unchecked")
protected MarshalerPrimitive(TypeReference typeReference, int nativeType) {
super(MarshalQueryablePrimitive.this, typeReference, nativeType);
// Turn primitives into wrappers, otherwise int.class.cast(Integer) will fail
mClass = wrapClassIfPrimitive((Class)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 createMarshaler(TypeReference managedType, int nativeType) {
return new MarshalerPrimitive(managedType, nativeType);
}
@Override
public boolean isTypeMappingSupported(TypeReference 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;
}
}