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