Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.hardware.camera2.marshal.impl;
     17 
     18 import android.hardware.camera2.marshal.Marshaler;
     19 import android.hardware.camera2.marshal.MarshalQueryable;
     20 import android.hardware.camera2.marshal.MarshalRegistry;
     21 import android.hardware.camera2.utils.TypeReference;
     22 import android.util.Log;
     23 
     24 import java.lang.reflect.Array;
     25 import java.nio.ByteBuffer;
     26 import java.util.ArrayList;
     27 
     28 import static android.hardware.camera2.impl.CameraMetadataNative.*;
     29 import static android.hardware.camera2.marshal.MarshalHelpers.*;
     30 
     31 /**
     32  * Marshal any array {@code T}.
     33  *
     34  * <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type
     35  * also has to exist.</p>
     36  *
     37  * <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a
     38  * built-in primitive (e.g. int[], float[], etc).</p>
     39 
     40  * @param <T> the type of the array (e.g. T = int[], or T = Rational[])
     41  */
     42 public class MarshalQueryableArray<T> implements MarshalQueryable<T> {
     43 
     44     private static final String TAG = MarshalQueryableArray.class.getSimpleName();
     45     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     46 
     47     private class MarshalerArray extends Marshaler<T> {
     48         private final Class<T> mClass;
     49         private final Marshaler<?> mComponentMarshaler;
     50         private final Class<?> mComponentClass;
     51 
     52         @SuppressWarnings("unchecked")
     53         protected MarshalerArray(TypeReference<T> typeReference, int nativeType) {
     54             super(MarshalQueryableArray.this, typeReference, nativeType);
     55 
     56             mClass = (Class<T>)typeReference.getRawType();
     57 
     58             TypeReference<?> componentToken = typeReference.getComponentType();
     59             mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType);
     60             mComponentClass = componentToken.getRawType();
     61         }
     62 
     63         @Override
     64         public void marshal(T value, ByteBuffer buffer) {
     65             int length = Array.getLength(value);
     66             for (int i = 0; i < length; ++i) {
     67                 marshalArrayElement(mComponentMarshaler, buffer, value, i);
     68             }
     69         }
     70 
     71         @Override
     72         public T unmarshal(ByteBuffer buffer) {
     73             Object array;
     74 
     75             int elementSize = mComponentMarshaler.getNativeSize();
     76 
     77             if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
     78                 int remaining = buffer.remaining();
     79                 int arraySize = remaining / elementSize;
     80 
     81                 if (remaining % elementSize != 0) {
     82                     throw new UnsupportedOperationException("Arrays for " + mTypeReference
     83                             + " must be packed tighly into a multiple of " + elementSize
     84                             + "; but there are " + (remaining % elementSize) + " left over bytes");
     85                 }
     86 
     87                 if (VERBOSE) {
     88                     Log.v(TAG, String.format(
     89                             "Attempting to unpack array (count = %d, element size = %d, bytes "
     90                             + "remaining = %d) for type %s",
     91                             arraySize, elementSize, remaining, mClass));
     92                 }
     93 
     94                 array = Array.newInstance(mComponentClass, arraySize);
     95                 for (int i = 0; i < arraySize; ++i) {
     96                     Object elem = mComponentMarshaler.unmarshal(buffer);
     97                     Array.set(array, i, elem);
     98                 }
     99             } else {
    100                 // Dynamic size, use an array list.
    101                 ArrayList<Object> arrayList = new ArrayList<Object>();
    102 
    103                 // Assumes array is packed tightly; no unused bytes allowed
    104                 while (buffer.hasRemaining()) {
    105                     Object elem = mComponentMarshaler.unmarshal(buffer);
    106                     arrayList.add(elem);
    107                 }
    108 
    109                 int arraySize = arrayList.size();
    110                 array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize));
    111             }
    112 
    113             if (buffer.remaining() != 0) {
    114                 Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
    115                         + mClass);
    116             }
    117 
    118             return mClass.cast(array);
    119         }
    120 
    121         @Override
    122         public int getNativeSize() {
    123             return NATIVE_SIZE_DYNAMIC;
    124         }
    125 
    126         @Override
    127         public int calculateMarshalSize(T value) {
    128             int elementSize = mComponentMarshaler.getNativeSize();
    129             int arrayLength = Array.getLength(value);
    130 
    131             if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
    132                 // The fast way. Every element size is uniform.
    133                 return elementSize * arrayLength;
    134             } else {
    135                 // The slow way. Accumulate size for each element.
    136                 int size = 0;
    137                 for (int i = 0; i < arrayLength; ++i) {
    138                     size += calculateElementMarshalSize(mComponentMarshaler, value, i);
    139                 }
    140 
    141                 return size;
    142             }
    143         }
    144 
    145         /*
    146          * Helpers to avoid compiler errors regarding types with wildcards (?)
    147          */
    148 
    149         @SuppressWarnings("unchecked")
    150         private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler,
    151                 ByteBuffer buffer, Object array, int index) {
    152             marshaler.marshal((TElem)Array.get(array, index), buffer);
    153         }
    154 
    155         @SuppressWarnings("unchecked")
    156         private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) {
    157             return arrayList.toArray((T[]) arrayDest);
    158         }
    159 
    160         @SuppressWarnings("unchecked")
    161         private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler,
    162                 Object array, int index) {
    163             Object elem = Array.get(array, index);
    164 
    165             return marshaler.calculateMarshalSize((TElem) elem);
    166         }
    167     }
    168 
    169     @Override
    170     public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
    171         return new MarshalerArray(managedType, nativeType);
    172     }
    173 
    174     @Override
    175     public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
    176         // support both ConcreteType[] and GenericType<ConcreteType>[]
    177         return managedType.getRawType().isArray();
    178 
    179         // TODO: Should this recurse deeper and check that there is
    180         // a valid marshaler for the ConcreteType as well?
    181     }
    182 }
    183