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 */
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.Range;
23
24import java.lang.reflect.Constructor;
25import java.lang.reflect.InvocationTargetException;
26import java.lang.reflect.ParameterizedType;
27import java.lang.reflect.Type;
28import java.nio.ByteBuffer;
29
30/**
31 * Marshal {@link Range} to/from any native type
32 */
33public class MarshalQueryableRange<T extends Comparable<? super T>>
34        implements MarshalQueryable<Range<T>> {
35    private static final int RANGE_COUNT = 2;
36
37    private class MarshalerRange extends Marshaler<Range<T>> {
38        private final Class<? super Range<T>> mClass;
39        private final Constructor<Range<T>> mConstructor;
40        /** Marshal the {@code T} inside of {@code Range<T>} */
41        private final Marshaler<T> mNestedTypeMarshaler;
42
43        @SuppressWarnings("unchecked")
44        protected MarshalerRange(TypeReference<Range<T>> typeReference,
45                int nativeType) {
46            super(MarshalQueryableRange.this, typeReference, nativeType);
47
48            mClass = typeReference.getRawType();
49
50            /*
51             * Lookup the actual type argument, e.g. Range<Integer> --> Integer
52             * and then get the marshaler for that managed type.
53             */
54            ParameterizedType paramType;
55            try {
56                paramType = (ParameterizedType) typeReference.getType();
57            } catch (ClassCastException e) {
58                throw new AssertionError("Raw use of Range is not supported", e);
59            }
60            Type actualTypeArgument = paramType.getActualTypeArguments()[0];
61
62            TypeReference<?> actualTypeArgToken =
63                    TypeReference.createSpecializedTypeReference(actualTypeArgument);
64
65            mNestedTypeMarshaler = (Marshaler<T>)MarshalRegistry.getMarshaler(
66                    actualTypeArgToken, mNativeType);
67            try {
68                mConstructor = (Constructor<Range<T>>)mClass.getConstructor(
69                        Comparable.class, Comparable.class);
70            } catch (NoSuchMethodException e) {
71                throw new AssertionError(e);
72            }
73        }
74
75        @Override
76        public void marshal(Range<T> value, ByteBuffer buffer) {
77            mNestedTypeMarshaler.marshal(value.getLower(), buffer);
78            mNestedTypeMarshaler.marshal(value.getUpper(), buffer);
79        }
80
81        @Override
82        public Range<T> unmarshal(ByteBuffer buffer) {
83            T lower = mNestedTypeMarshaler.unmarshal(buffer);
84            T upper = mNestedTypeMarshaler.unmarshal(buffer);
85
86            try {
87                return mConstructor.newInstance(lower, upper);
88            } catch (InstantiationException e) {
89                throw new AssertionError(e);
90            } catch (IllegalAccessException e) {
91                throw new AssertionError(e);
92            } catch (IllegalArgumentException e) {
93                throw new AssertionError(e);
94            } catch (InvocationTargetException e) {
95                throw new AssertionError(e);
96            }
97        }
98
99        @Override
100        public int getNativeSize() {
101            int nestedSize = mNestedTypeMarshaler.getNativeSize();
102
103            if (nestedSize != NATIVE_SIZE_DYNAMIC) {
104                return nestedSize * RANGE_COUNT;
105            } else {
106                return NATIVE_SIZE_DYNAMIC;
107            }
108        }
109
110        @Override
111        public int calculateMarshalSize(Range<T> value) {
112            int nativeSize = getNativeSize();
113
114            if (nativeSize != NATIVE_SIZE_DYNAMIC) {
115                return nativeSize;
116            } else {
117                int lowerSize = mNestedTypeMarshaler.calculateMarshalSize(value.getLower());
118                int upperSize = mNestedTypeMarshaler.calculateMarshalSize(value.getUpper());
119
120                return lowerSize + upperSize;
121            }
122        }
123    }
124
125    @Override
126    public Marshaler<Range<T>> createMarshaler(TypeReference<Range<T>> managedType,
127            int nativeType) {
128        return new MarshalerRange(managedType, nativeType);
129    }
130
131    @Override
132    public boolean isTypeMappingSupported(TypeReference<Range<T>> managedType, int nativeType) {
133        return (Range.class.equals(managedType.getRawType()));
134    }
135
136}
137