blob: 22b87ef68592fb86290d65d423097d146d2124cf [file] [log] [blame]
Igor Murashkin3c40a042014-04-22 15:05:50 -07001/*
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 */
16package android.hardware.camera2.marshal.impl;
17
18import android.hardware.camera2.marshal.Marshaler;
19import android.hardware.camera2.marshal.MarshalQueryable;
20import android.hardware.camera2.marshal.MarshalRegistry;
21import android.hardware.camera2.utils.TypeReference;
22import android.util.Log;
23
24import java.lang.reflect.Array;
25import java.nio.ByteBuffer;
26import java.util.ArrayList;
27
28import static android.hardware.camera2.impl.CameraMetadataNative.*;
29import 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 */
42public 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}