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") MarshalerArray(TypeReference<T> typeReference, int nativeType)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 marshal(T value, ByteBuffer buffer)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 unmarshal(ByteBuffer buffer)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 getNativeSize()119 public int getNativeSize() { 120 return NATIVE_SIZE_DYNAMIC; 121 } 122 123 @Override calculateMarshalSize(T value)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") marshalArrayElement(Marshaler<TElem> marshaler, ByteBuffer buffer, Object array, int index)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") copyListToArray(ArrayList<?> arrayList, Object arrayDest)153 private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) { 154 return arrayList.toArray((T[]) arrayDest); 155 } 156 157 @SuppressWarnings("unchecked") calculateElementMarshalSize(Marshaler<TElem> marshaler, Object array, int index)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 createMarshaler(TypeReference<T> managedType, int nativeType)167 public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) { 168 return new MarshalerArray(managedType, nativeType); 169 } 170 171 @Override isTypeMappingSupported(TypeReference<T> managedType, int nativeType)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