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;
17 
18 import static android.hardware.camera2.impl.CameraMetadataNative.*;
19 import static com.android.internal.util.Preconditions.*;
20 
21 import android.hardware.camera2.impl.CameraMetadataNative;
22 import android.util.Rational;
23 
24 /**
25  * Static functions in order to help implementing various marshaler functionality.
26  *
27  * <p>The intention is to statically import everything from this file into another file when
28  * implementing a new marshaler (or marshal queryable).</p>
29  *
30  * <p>The helpers are centered around providing primitive knowledge of the native types,
31  * such as the native size, the managed class wrappers, and various precondition checks.</p>
32  */
33 public final class MarshalHelpers {
34 
35     public static final int SIZEOF_BYTE = 1;
36     public static final int SIZEOF_INT32 = Integer.SIZE / Byte.SIZE;
37     public static final int SIZEOF_INT64 = Long.SIZE / Byte.SIZE;
38     public static final int SIZEOF_FLOAT = Float.SIZE / Byte.SIZE;
39     public static final int SIZEOF_DOUBLE = Double.SIZE / Byte.SIZE;
40     public static final int SIZEOF_RATIONAL = SIZEOF_INT32 * 2;
41 
42     /**
43      * Get the size in bytes for the native camera metadata type.
44      *
45      * <p>This used to determine how many bytes it would take to encode/decode a single value
46      * of that {@link nativeType}.</p>
47      *
48      * @param nativeType the native type, e.g.
49      *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
50      * @return size in bytes >= 1
51      *
52      * @throws UnsupportedOperationException if nativeType was not one of the built-in types
53      */
getPrimitiveTypeSize(int nativeType)54     public static int getPrimitiveTypeSize(int nativeType) {
55         switch (nativeType) {
56             case TYPE_BYTE:
57                 return SIZEOF_BYTE;
58             case TYPE_INT32:
59                 return SIZEOF_INT32;
60             case TYPE_FLOAT:
61                 return SIZEOF_FLOAT;
62             case TYPE_INT64:
63                 return SIZEOF_INT64;
64             case TYPE_DOUBLE:
65                 return SIZEOF_DOUBLE;
66             case TYPE_RATIONAL:
67                 return SIZEOF_RATIONAL;
68         }
69 
70         throw new UnsupportedOperationException("Unknown type, can't get size for "
71                 + nativeType);
72     }
73 
74 
75     /**
76      * Ensure that the {@code klass} is one of the metadata-primitive classes.
77      *
78      * @param klass a non-{@code null} reference
79      * @return {@code klass} instance
80      *
81      * @throws UnsupportedOperationException if klass was not one of the built-in classes
82      * @throws NullPointerException if klass was null
83      *
84      * @see #isPrimitiveClass
85      */
checkPrimitiveClass(Class<T> klass)86     public static <T> Class<T> checkPrimitiveClass(Class<T> klass) {
87         checkNotNull(klass, "klass must not be null");
88 
89         if (isPrimitiveClass(klass)) {
90             return klass;
91         }
92 
93         throw new UnsupportedOperationException("Unsupported class '" + klass +
94                 "'; expected a metadata primitive class");
95     }
96 
97     /**
98      * Checks whether or not {@code klass} is one of the metadata-primitive classes.
99      *
100      * <p>The following types (whether boxed or unboxed) are considered primitive:
101      * <ul>
102      * <li>byte
103      * <li>int
104      * <li>float
105      * <li>double
106      * <li>Rational
107      * </ul>
108      * </p>
109      *
110      * <p>This doesn't strictly follow the java understanding of primitive since
111      * boxed objects are included, Rational is included, and other types such as char and
112      * short are not included.</p>
113      *
114      * @param klass a {@link Class} instance; using {@code null} will return {@code false}
115      * @return {@code true} if primitive, {@code false} otherwise
116      */
isPrimitiveClass(Class<T> klass)117     public static <T> boolean isPrimitiveClass(Class<T> klass) {
118         if (klass == null) {
119             return false;
120         }
121 
122         if (klass == byte.class || klass == Byte.class) {
123             return true;
124         } else if (klass == int.class || klass == Integer.class) {
125             return true;
126         } else if (klass == float.class || klass == Float.class) {
127             return true;
128         } else if (klass == long.class || klass == Long.class) {
129             return true;
130         } else if (klass == double.class || klass == Double.class) {
131             return true;
132         } else if (klass == Rational.class) {
133             return true;
134         }
135 
136         return false;
137     }
138 
139     /**
140      * Wrap {@code klass} with its wrapper variant if it was a {@code Class} corresponding
141      * to a Java primitive.
142      *
143      * <p>Non-primitive classes are passed through as-is.</p>
144      *
145      * <p>For example, for a primitive {@code int.class => Integer.class},
146      * but for a non-primitive {@code Rational.class => Rational.class}.</p>
147      *
148      * @param klass a {@code Class} reference
149      *
150      * @return wrapped class object, or same class object if non-primitive
151      */
152     @SuppressWarnings("unchecked")
wrapClassIfPrimitive(Class<T> klass)153     public static <T> Class<T> wrapClassIfPrimitive(Class<T> klass) {
154         if (klass == byte.class) {
155             return (Class<T>)Byte.class;
156         } else if (klass == int.class) {
157             return (Class<T>)Integer.class;
158         } else if (klass == float.class) {
159             return (Class<T>)Float.class;
160         } else if (klass == long.class) {
161             return (Class<T>)Long.class;
162         } else if (klass == double.class) {
163             return (Class<T>)Double.class;
164         }
165 
166         return klass;
167     }
168 
169     /**
170      * Return a human-readable representation of the {@code nativeType}, e.g. "TYPE_INT32"
171      *
172      * <p>Out-of-range values return a string with "UNKNOWN" as the prefix.</p>
173      *
174      * @param nativeType the native type
175      *
176      * @return human readable type name
177      */
toStringNativeType(int nativeType)178     public static String toStringNativeType(int nativeType) {
179         switch (nativeType) {
180             case TYPE_BYTE:
181                 return "TYPE_BYTE";
182             case TYPE_INT32:
183                 return "TYPE_INT32";
184             case TYPE_FLOAT:
185                 return "TYPE_FLOAT";
186             case TYPE_INT64:
187                 return "TYPE_INT64";
188             case TYPE_DOUBLE:
189                 return "TYPE_DOUBLE";
190             case TYPE_RATIONAL:
191                 return "TYPE_RATIONAL";
192         }
193 
194         return "UNKNOWN(" + nativeType + ")";
195     }
196 
197     /**
198      * Ensure that the {@code nativeType} is one of the native types supported
199      * by {@link CameraMetadataNative}.
200      *
201      * @param nativeType the native type
202      *
203      * @return the native type
204      *
205      * @throws UnsupportedOperationException if the native type was invalid
206      */
checkNativeType(int nativeType)207     public static int checkNativeType(int nativeType) {
208         switch (nativeType) {
209             case TYPE_BYTE:
210             case TYPE_INT32:
211             case TYPE_FLOAT:
212             case TYPE_INT64:
213             case TYPE_DOUBLE:
214             case TYPE_RATIONAL:
215                 return nativeType;
216         }
217 
218         throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
219     }
220 
221     /**
222      * Ensure that the expected and actual native types are equal.
223      *
224      * @param expectedNativeType the expected native type
225      * @param actualNativeType the actual native type
226      * @return the actual native type
227      *
228      * @throws UnsupportedOperationException if the types are not equal
229      */
checkNativeTypeEquals(int expectedNativeType, int actualNativeType)230     public static int checkNativeTypeEquals(int expectedNativeType, int actualNativeType) {
231         if (expectedNativeType != actualNativeType) {
232             throw new UnsupportedOperationException(
233                     String.format("Expected native type %d, but got %d",
234                             expectedNativeType, actualNativeType));
235         }
236 
237         return actualNativeType;
238     }
239 
MarshalHelpers()240     private MarshalHelpers() {
241         throw new AssertionError();
242     }
243 }
244