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 /**
     29  * Marshal any array {@code T}.
     30  *
     31  * <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type
     32  * also has to exist.</p>
     33  *
     34  * <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a
     35  * built-in primitive (e.g. int[], float[], etc).</p>
     36 
     37  * @param <T> the type of the array (e.g. T = int[], or T = Rational[])
     38  */
     39 public class MarshalQueryableArray<T> implements MarshalQueryable<T> {
     40 
     41     private static final String TAG = MarshalQueryableArray.class.getSimpleName();
     42     private static final boolean DEBUG = false;
     43 
     44     private class MarshalerArray extends Marshaler<T> {
     45         private final Class<T> mClass;
     46         private final Marshaler<?> mComponentMarshaler;
     47         private final Class<?> mComponentClass;
     48 
     49         @SuppressWarnings("unchecked")
     50         protected MarshalerArray(TypeReference<T> typeReference, int nativeType) {
     51             super(MarshalQueryableArray.this, typeReference, nativeType);
     52 
     53             mClass = (Class<T>)typeReference.getRawType();
     54 
     55             TypeReference<?> componentToken = typeReference.getComponentType();
     56             mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType);
     57             mComponentClass = componentToken.getRawType();
     58         }
     59 
     60         @Override
     61         public void marshal(T value, ByteBuffer buffer) {
     62             int length = Array.getLength(value);
     63             for (int i = 0; i < length; ++i) {
     64                 marshalArrayElement(mComponentMarshaler, buffer, value, i);
     65             }
     66         }
     67 
     68         @Override
     69         public T unmarshal(ByteBuffer buffer) {
     70             Object array;
     71 
     72             int elementSize = mComponentMarshaler.getNativeSize();
     73 
     74             if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
     75                 int remaining = buffer.remaining();
     76                 int arraySize = remaining / elementSize;
     77 
     78                 if (remaining % elementSize != 0) {
     79                     throw new UnsupportedOperationException("Arrays for " + mTypeReference
     80                             + " must be packed tighly into a multiple of " + elementSize
     81                             + "; but there are " + (remaining % elementSize) + " left over bytes");
     82                 }
     83 
     84                 if (DEBUG) {
     85                     Log.v(TAG, String.format(
     86                             "Attempting to unpack array (count = %d, element size = %d, bytes "
     87                             + "remaining = %d) for type %s",
     88                             arraySize, elementSize, remaining, mClass));
     89                 }
     90 
     91                 array = Array.newInstance(mComponentClass, arraySize);
     92                 for (int i = 0; i < arraySize; ++i) {
     93                     Object elem = mComponentMarshaler.unmarshal(buffer);
     94                     Array.set(array, i, elem);
     95                 }
     96             } else {
     97                 // Dynamic size, use an array list.
     98                 ArrayList<Object> arrayList = new ArrayList<Object>();
     99 
    100                 // Assumes array is packed tightly; no unused bytes allowed
    101                 while (buffer.hasRemaining()) {
    102                     Object elem = mComponentMarshaler.unmarshal(buffer);
    103                     arrayList.add(elem);
    104                 }
    105 
    106                 int arraySize = arrayList.size();
    107                 array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize));
    108             }
    109 
    110             if (buffer.remaining() != 0) {
    111                 Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
    112                         + mClass);
    113             }
    114 
    115             return mClass.cast(array);
    116         }
    117 
    118         @Override
    119         public int getNativeSize() {
    120             return NATIVE_SIZE_DYNAMIC;
    121         }
    122 
    123         @Override
    124         public int calculateMarshalSize(T value) {
    125             int elementSize = mComponentMarshaler.getNativeSize();
    126             int arrayLength = Array.getLength(value);
    127 
    128             if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
    129                 // The fast way. Every element size is uniform.
    130                 return elementSize * arrayLength;
    131             } else {
    132                 // The slow way. Accumulate size for each element.
    133                 int size = 0;
    134                 for (int i = 0; i < arrayLength; ++i) {
    135                     size += calculateElementMarshalSize(mComponentMarshaler, value, i);
    136                 }
    137 
    138                 return size;
    139             }
    140         }
    141 
    142         /*
    143          * Helpers to avoid compiler errors regarding types with wildcards (?)
    144          */
    145 
    146         @SuppressWarnings("unchecked")
    147         private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler,
    148                 ByteBuffer buffer, Object array, int index) {
    149             marshaler.marshal((TElem)Array.get(array, index), buffer);
    150         }
    151 
    152         @SuppressWarnings("unchecked")
    153         private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) {
    154             return arrayList.toArray((T[]) arrayDest);
    155         }
    156 
    157         @SuppressWarnings("unchecked")
    158         private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler,
    159                 Object array, int index) {
    160             Object elem = Array.get(array, index);
    161 
    162             return marshaler.calculateMarshalSize((TElem) elem);
    163         }
    164     }
    165 
    166     @Override
    167     public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
    168         return new MarshalerArray(managedType, nativeType);
    169     }
    170 
    171     @Override
    172     public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
    173         // support both ConcreteType[] and GenericType<ConcreteType>[]
    174         return managedType.getRawType().isArray();
    175 
    176         // TODO: Should this recurse deeper and check that there is
    177         // a valid marshaler for the ConcreteType as well?
    178     }
    179 }
    180