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 unboxed 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      * </ul>
107      * </p>
108      *
109      * @param klass a {@link Class} instance; using {@code null} will return {@code false}
110      * @return {@code true} if primitive, {@code false} otherwise
111      */
isUnwrappedPrimitiveClass(Class<?> klass)112     public static boolean isUnwrappedPrimitiveClass(Class<?> klass) {
113         if (klass == null) {
114             return false;
115         }
116 
117         if (klass == byte.class) {
118             return true;
119         } else if (klass == int.class) {
120             return true;
121         } else if (klass == float.class) {
122             return true;
123         } else if (klass == long.class) {
124             return true;
125         } else if (klass == double.class) {
126             return true;
127         }
128         return false;
129     }
130 
131     /**
132      * Checks whether or not {@code klass} is one of the metadata-primitive classes.
133      *
134      * <p>The following types (whether boxed or unboxed) are considered primitive:
135      * <ul>
136      * <li>byte
137      * <li>int
138      * <li>float
139      * <li>double
140      * <li>Rational
141      * </ul>
142      * </p>
143      *
144      * <p>This doesn't strictly follow the java understanding of primitive since
145      * boxed objects are included, Rational is included, and other types such as char and
146      * short are not included.</p>
147      *
148      * @param klass a {@link Class} instance; using {@code null} will return {@code false}
149      * @return {@code true} if primitive, {@code false} otherwise
150      */
isPrimitiveClass(Class<T> klass)151     public static <T> boolean isPrimitiveClass(Class<T> klass) {
152         if (klass == null) {
153             return false;
154         }
155 
156         if (klass == byte.class || klass == Byte.class) {
157             return true;
158         } else if (klass == int.class || klass == Integer.class) {
159             return true;
160         } else if (klass == float.class || klass == Float.class) {
161             return true;
162         } else if (klass == long.class || klass == Long.class) {
163             return true;
164         } else if (klass == double.class || klass == Double.class) {
165             return true;
166         } else if (klass == Rational.class) {
167             return true;
168         }
169 
170         return false;
171     }
172 
173     /**
174      * Wrap {@code klass} with its wrapper variant if it was a {@code Class} corresponding
175      * to a Java primitive.
176      *
177      * <p>Non-primitive classes are passed through as-is.</p>
178      *
179      * <p>For example, for a primitive {@code int.class => Integer.class},
180      * but for a non-primitive {@code Rational.class => Rational.class}.</p>
181      *
182      * @param klass a {@code Class} reference
183      *
184      * @return wrapped class object, or same class object if non-primitive
185      */
186     @SuppressWarnings("unchecked")
wrapClassIfPrimitive(Class<T> klass)187     public static <T> Class<T> wrapClassIfPrimitive(Class<T> klass) {
188         if (klass == byte.class) {
189             return (Class<T>)Byte.class;
190         } else if (klass == int.class) {
191             return (Class<T>)Integer.class;
192         } else if (klass == float.class) {
193             return (Class<T>)Float.class;
194         } else if (klass == long.class) {
195             return (Class<T>)Long.class;
196         } else if (klass == double.class) {
197             return (Class<T>)Double.class;
198         }
199 
200         return klass;
201     }
202 
203     /**
204      * Return a human-readable representation of the {@code nativeType}, e.g. "TYPE_INT32"
205      *
206      * <p>Out-of-range values return a string with "UNKNOWN" as the prefix.</p>
207      *
208      * @param nativeType the native type
209      *
210      * @return human readable type name
211      */
toStringNativeType(int nativeType)212     public static String toStringNativeType(int nativeType) {
213         switch (nativeType) {
214             case TYPE_BYTE:
215                 return "TYPE_BYTE";
216             case TYPE_INT32:
217                 return "TYPE_INT32";
218             case TYPE_FLOAT:
219                 return "TYPE_FLOAT";
220             case TYPE_INT64:
221                 return "TYPE_INT64";
222             case TYPE_DOUBLE:
223                 return "TYPE_DOUBLE";
224             case TYPE_RATIONAL:
225                 return "TYPE_RATIONAL";
226         }
227 
228         return "UNKNOWN(" + nativeType + ")";
229     }
230 
231     /**
232      * Ensure that the {@code nativeType} is one of the native types supported
233      * by {@link CameraMetadataNative}.
234      *
235      * @param nativeType the native type
236      *
237      * @return the native type
238      *
239      * @throws UnsupportedOperationException if the native type was invalid
240      */
checkNativeType(int nativeType)241     public static int checkNativeType(int nativeType) {
242         switch (nativeType) {
243             case TYPE_BYTE:
244             case TYPE_INT32:
245             case TYPE_FLOAT:
246             case TYPE_INT64:
247             case TYPE_DOUBLE:
248             case TYPE_RATIONAL:
249                 return nativeType;
250         }
251 
252         throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
253     }
254 
255     /**
256      * Get the unboxed primitive type corresponding to nativeType
257      *
258      * @param nativeType the native type (RATIONAL not included)
259      *
260      * @return the native type class
261      *
262      * @throws UnsupportedOperationException if the native type was invalid
263      */
getPrimitiveTypeClass(int nativeType)264     public static Class<?> getPrimitiveTypeClass(int nativeType) {
265         switch (nativeType) {
266             case TYPE_BYTE:
267                 return byte.class;
268             case TYPE_INT32:
269                 return int.class;
270             case TYPE_FLOAT:
271                 return float.class;
272             case TYPE_INT64:
273                 return long.class;
274             case TYPE_DOUBLE:
275                 return double.class;
276         }
277 
278         throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
279     }
280 
281     /**
282      * Ensure that the expected and actual native types are equal.
283      *
284      * @param expectedNativeType the expected native type
285      * @param actualNativeType the actual native type
286      * @return the actual native type
287      *
288      * @throws UnsupportedOperationException if the types are not equal
289      */
checkNativeTypeEquals(int expectedNativeType, int actualNativeType)290     public static int checkNativeTypeEquals(int expectedNativeType, int actualNativeType) {
291         if (expectedNativeType != actualNativeType) {
292             throw new UnsupportedOperationException(
293                     String.format("Expected native type %d, but got %d",
294                             expectedNativeType, actualNativeType));
295         }
296 
297         return actualNativeType;
298     }
299 
MarshalHelpers()300     private MarshalHelpers() {
301         throw new AssertionError();
302     }
303 }
304