13c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin/*
23c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Copyright (C) 2014 The Android Open Source Project
33c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
43c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
53c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * you may not use this file except in compliance with the License.
63c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * You may obtain a copy of the License at
73c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
83c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
93c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
103c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Unless required by applicable law or agreed to in writing, software
113c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
123c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * See the License for the specific language governing permissions and
143c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * limitations under the License.
153c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */
163c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinpackage android.hardware.camera2.marshal.impl;
173c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
183c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.Marshaler;
193c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.MarshalQueryable;
203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.MarshalRegistry;
213c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.utils.TypeReference;
223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.util.Log;
233c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
243c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.lang.reflect.Array;
253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.nio.ByteBuffer;
263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.util.ArrayList;
273c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
283c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport static android.hardware.camera2.impl.CameraMetadataNative.*;
293c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport static android.hardware.camera2.marshal.MarshalHelpers.*;
303c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
313c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin/**
323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Marshal any array {@code T}.
333c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
343c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type
353c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * also has to exist.</p>
363c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin *
373c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a
383c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * built-in primitive (e.g. int[], float[], etc).</p>
393c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
403c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * @param <T> the type of the array (e.g. T = int[], or T = Rational[])
413c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */
423c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinpublic class MarshalQueryableArray<T> implements MarshalQueryable<T> {
433c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
443c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    private static final String TAG = MarshalQueryableArray.class.getSimpleName();
453c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
463c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
473c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    private class MarshalerArray extends Marshaler<T> {
483c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private final Class<T> mClass;
493c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private final Marshaler<?> mComponentMarshaler;
503c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private final Class<?> mComponentClass;
513c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
523c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @SuppressWarnings("unchecked")
533c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        protected MarshalerArray(TypeReference<T> typeReference, int nativeType) {
543c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            super(MarshalQueryableArray.this, typeReference, nativeType);
553c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
563c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            mClass = (Class<T>)typeReference.getRawType();
573c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
583c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            TypeReference<?> componentToken = typeReference.getComponentType();
593c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType);
603c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            mComponentClass = componentToken.getRawType();
613c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
623c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
633c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
643c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public void marshal(T value, ByteBuffer buffer) {
653c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            int length = Array.getLength(value);
663c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            for (int i = 0; i < length; ++i) {
673c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                marshalArrayElement(mComponentMarshaler, buffer, value, i);
683c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
693c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
703c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
713c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
723c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public T unmarshal(ByteBuffer buffer) {
733c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            Object array;
743c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
753c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            int elementSize = mComponentMarshaler.getNativeSize();
763c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
773c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
783c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int remaining = buffer.remaining();
793c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int arraySize = remaining / elementSize;
803c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
813c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                if (remaining % elementSize != 0) {
823c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    throw new UnsupportedOperationException("Arrays for " + mTypeReference
833c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            + " must be packed tighly into a multiple of " + elementSize
843c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            + "; but there are " + (remaining % elementSize) + " left over bytes");
853c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
863c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
873c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                if (VERBOSE) {
883c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Log.v(TAG, String.format(
893c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            "Attempting to unpack array (count = %d, element size = %d, bytes "
903c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            + "remaining = %d) for type %s",
913c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                            arraySize, elementSize, remaining, mClass));
923c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
933c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
943c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                array = Array.newInstance(mComponentClass, arraySize);
953c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                for (int i = 0; i < arraySize; ++i) {
963c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Object elem = mComponentMarshaler.unmarshal(buffer);
973c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Array.set(array, i, elem);
983c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
993c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } else {
1003c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // Dynamic size, use an array list.
1013c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                ArrayList<Object> arrayList = new ArrayList<Object>();
1023c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1033c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // Assumes array is packed tightly; no unused bytes allowed
1043c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                while (buffer.hasRemaining()) {
1053c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    Object elem = mComponentMarshaler.unmarshal(buffer);
1063c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    arrayList.add(elem);
1073c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
1083c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1093c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int arraySize = arrayList.size();
1103c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize));
1113c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
1123c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1133c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            if (buffer.remaining() != 0) {
1143c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
1153c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                        + mClass);
1163c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
1173c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1183c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            return mClass.cast(array);
1193c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1213c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
1223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public int getNativeSize() {
1233c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            return NATIVE_SIZE_DYNAMIC;
1243c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @Override
1273c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        public int calculateMarshalSize(T value) {
1283c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            int elementSize = mComponentMarshaler.getNativeSize();
1293c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            int arrayLength = Array.getLength(value);
1303c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1313c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
1323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // The fast way. Every element size is uniform.
1333c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                return elementSize * arrayLength;
1343c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            } else {
1353c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                // The slow way. Accumulate size for each element.
1363c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                int size = 0;
1373c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                for (int i = 0; i < arrayLength; ++i) {
1383c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                    size += calculateElementMarshalSize(mComponentMarshaler, value, i);
1393c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                }
1403c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1413c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                return size;
1423c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            }
1433c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1443c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1453c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        /*
1463c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin         * Helpers to avoid compiler errors regarding types with wildcards (?)
1473c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin         */
1483c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1493c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @SuppressWarnings("unchecked")
1503c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler,
1513c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                ByteBuffer buffer, Object array, int index) {
1523c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            marshaler.marshal((TElem)Array.get(array, index), buffer);
1533c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1543c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1553c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @SuppressWarnings("unchecked")
1563c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) {
1573c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            return arrayList.toArray((T[]) arrayDest);
1583c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1593c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1603c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        @SuppressWarnings("unchecked")
1613c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler,
1623c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin                Object array, int index) {
1633c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            Object elem = Array.get(array, index);
1643c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1653c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin            return marshaler.calculateMarshalSize((TElem) elem);
1663c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        }
1673c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    }
1683c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1693c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    @Override
1703c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
1713c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        return new MarshalerArray(managedType, nativeType);
1723c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    }
1733c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1743c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    @Override
1753c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
1763c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        // support both ConcreteType[] and GenericType<ConcreteType>[]
1773c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        return managedType.getRawType().isArray();
1783c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
1793c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        // TODO: Should this recurse deeper and check that there is
1803c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin        // a valid marshaler for the ConcreteType as well?
1813c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin    }
1823c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin}
183