1 /*
2  * Copyright (C) 2013 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 
17 package android.hardware.camera2.impl;
18 
19 import android.graphics.ImageFormat;
20 import android.graphics.Point;
21 import android.graphics.Rect;
22 import android.hardware.camera2.CameraCharacteristics;
23 import android.hardware.camera2.CaptureRequest;
24 import android.hardware.camera2.CaptureResult;
25 import android.hardware.camera2.marshal.Marshaler;
26 import android.hardware.camera2.marshal.MarshalQueryable;
27 import android.hardware.camera2.marshal.MarshalRegistry;
28 import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
29 import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
30 import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
31 import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
32 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
33 import android.hardware.camera2.marshal.impl.MarshalQueryableHighSpeedVideoConfiguration;
34 import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
35 import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
36 import android.hardware.camera2.marshal.impl.MarshalQueryablePair;
37 import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
38 import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
39 import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
40 import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
41 import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
42 import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
43 import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
44 import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
45 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
46 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
47 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
48 import android.hardware.camera2.params.Face;
49 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
50 import android.hardware.camera2.params.LensShadingMap;
51 import android.hardware.camera2.params.StreamConfiguration;
52 import android.hardware.camera2.params.StreamConfigurationDuration;
53 import android.hardware.camera2.params.StreamConfigurationMap;
54 import android.hardware.camera2.params.TonemapCurve;
55 import android.hardware.camera2.utils.TypeReference;
56 import android.location.Location;
57 import android.location.LocationManager;
58 import android.os.Parcelable;
59 import android.os.Parcel;
60 import android.util.Log;
61 import android.util.Size;
62 
63 import com.android.internal.util.Preconditions;
64 
65 import java.io.IOException;
66 import java.nio.ByteBuffer;
67 import java.nio.ByteOrder;
68 import java.util.ArrayList;
69 import java.util.HashMap;
70 
71 /**
72  * Implementation of camera metadata marshal/unmarshal across Binder to
73  * the camera service
74  */
75 public class CameraMetadataNative implements Parcelable {
76 
77     public static class Key<T> {
78         private boolean mHasTag;
79         private int mTag;
80         private final Class<T> mType;
81         private final TypeReference<T> mTypeReference;
82         private final String mName;
83         private final int mHash;
84         /**
85          * Visible for testing only.
86          *
87          * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
88          * for application code or vendor-extended keys.</p>
89          */
Key(String name, Class<T> type)90         public Key(String name, Class<T> type) {
91             if (name == null) {
92                 throw new NullPointerException("Key needs a valid name");
93             } else if (type == null) {
94                 throw new NullPointerException("Type needs to be non-null");
95             }
96             mName = name;
97             mType = type;
98             mTypeReference = TypeReference.createSpecializedTypeReference(type);
99             mHash = mName.hashCode() ^ mTypeReference.hashCode();
100         }
101 
102         /**
103          * Visible for testing only.
104          *
105          * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
106          * for application code or vendor-extended keys.</p>
107          */
108         @SuppressWarnings("unchecked")
Key(String name, TypeReference<T> typeReference)109         public Key(String name, TypeReference<T> typeReference) {
110             if (name == null) {
111                 throw new NullPointerException("Key needs a valid name");
112             } else if (typeReference == null) {
113                 throw new NullPointerException("TypeReference needs to be non-null");
114             }
115             mName = name;
116             mType = (Class<T>)typeReference.getRawType();
117             mTypeReference = typeReference;
118             mHash = mName.hashCode() ^ mTypeReference.hashCode();
119         }
120 
121         /**
122          * Return a camelCase, period separated name formatted like:
123          * {@code "root.section[.subsections].name"}.
124          *
125          * <p>Built-in keys exposed by the Android SDK are always prefixed with {@code "android."};
126          * keys that are device/platform-specific are prefixed with {@code "com."}.</p>
127          *
128          * <p>For example, {@code CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP} would
129          * have a name of {@code "android.scaler.streamConfigurationMap"}; whereas a device
130          * specific key might look like {@code "com.google.nexus.data.private"}.</p>
131          *
132          * @return String representation of the key name
133          */
getName()134         public final String getName() {
135             return mName;
136         }
137 
138         /**
139          * {@inheritDoc}
140          */
141         @Override
hashCode()142         public final int hashCode() {
143             return mHash;
144         }
145 
146         /**
147          * Compare this key against other native keys, request keys, result keys, and
148          * characteristics keys.
149          *
150          * <p>Two keys are considered equal if their name and type reference are equal.</p>
151          *
152          * <p>Note that the equality against non-native keys is one-way. A native key may be equal
153          * to a result key; but that same result key will not be equal to a native key.</p>
154          */
155         @SuppressWarnings("rawtypes")
156         @Override
equals(Object o)157         public final boolean equals(Object o) {
158             if (this == o) {
159                 return true;
160             }
161 
162             if (o == null || this.hashCode() != o.hashCode()) {
163                 return false;
164             }
165 
166             Key<?> lhs;
167 
168             if (o instanceof CaptureResult.Key) {
169                 lhs = ((CaptureResult.Key)o).getNativeKey();
170             } else if (o instanceof CaptureRequest.Key) {
171                 lhs = ((CaptureRequest.Key)o).getNativeKey();
172             } else if (o instanceof CameraCharacteristics.Key) {
173                 lhs = ((CameraCharacteristics.Key)o).getNativeKey();
174             } else if ((o instanceof Key)) {
175                 lhs = (Key<?>)o;
176             } else {
177                 return false;
178             }
179 
180             return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
181         }
182 
183         /**
184          * <p>
185          * Get the tag corresponding to this key. This enables insertion into the
186          * native metadata.
187          * </p>
188          *
189          * <p>This value is looked up the first time, and cached subsequently.</p>
190          *
191          * @return The tag numeric value corresponding to the string
192          */
getTag()193         public final int getTag() {
194             if (!mHasTag) {
195                 mTag = CameraMetadataNative.getTag(mName);
196                 mHasTag = true;
197             }
198             return mTag;
199         }
200 
201         /**
202          * Get the raw class backing the type {@code T} for this key.
203          *
204          * <p>The distinction is only important if {@code T} is a generic, e.g.
205          * {@code Range<Integer>} since the nested type will be erased.</p>
206          */
getType()207         public final Class<T> getType() {
208             // TODO: remove this; other places should use #getTypeReference() instead
209             return mType;
210         }
211 
212         /**
213          * Get the type reference backing the type {@code T} for this key.
214          *
215          * <p>The distinction is only important if {@code T} is a generic, e.g.
216          * {@code Range<Integer>} since the nested type will be retained.</p>
217          */
getTypeReference()218         public final TypeReference<T> getTypeReference() {
219             return mTypeReference;
220         }
221     }
222 
223     private static final String TAG = "CameraMetadataJV";
224     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
225     // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h
226     public static final int NATIVE_JPEG_FORMAT = 0x21;
227 
228     private static final String CELLID_PROCESS = "CELLID";
229     private static final String GPS_PROCESS = "GPS";
230     private static final int FACE_LANDMARK_SIZE = 6;
231 
translateLocationProviderToProcess(final String provider)232     private static String translateLocationProviderToProcess(final String provider) {
233         if (provider == null) {
234             return null;
235         }
236         switch(provider) {
237             case LocationManager.GPS_PROVIDER:
238                 return GPS_PROCESS;
239             case LocationManager.NETWORK_PROVIDER:
240                 return CELLID_PROCESS;
241             default:
242                 return null;
243         }
244     }
245 
translateProcessToLocationProvider(final String process)246     private static String translateProcessToLocationProvider(final String process) {
247         if (process == null) {
248             return null;
249         }
250         switch(process) {
251             case GPS_PROCESS:
252                 return LocationManager.GPS_PROVIDER;
253             case CELLID_PROCESS:
254                 return LocationManager.NETWORK_PROVIDER;
255             default:
256                 return null;
257         }
258     }
259 
CameraMetadataNative()260     public CameraMetadataNative() {
261         super();
262         mMetadataPtr = nativeAllocate();
263         if (mMetadataPtr == 0) {
264             throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
265         }
266     }
267 
268     /**
269      * Copy constructor - clone metadata
270      */
CameraMetadataNative(CameraMetadataNative other)271     public CameraMetadataNative(CameraMetadataNative other) {
272         super();
273         mMetadataPtr = nativeAllocateCopy(other);
274         if (mMetadataPtr == 0) {
275             throw new OutOfMemoryError("Failed to allocate native CameraMetadata");
276         }
277     }
278 
279     /**
280      * Move the contents from {@code other} into a new camera metadata instance.</p>
281      *
282      * <p>After this call, {@code other} will become empty.</p>
283      *
284      * @param other the previous metadata instance which will get pilfered
285      * @return a new metadata instance with the values from {@code other} moved into it
286      */
move(CameraMetadataNative other)287     public static CameraMetadataNative move(CameraMetadataNative other) {
288         CameraMetadataNative newObject = new CameraMetadataNative();
289         newObject.swap(other);
290         return newObject;
291     }
292 
293     public static final Parcelable.Creator<CameraMetadataNative> CREATOR =
294             new Parcelable.Creator<CameraMetadataNative>() {
295         @Override
296         public CameraMetadataNative createFromParcel(Parcel in) {
297             CameraMetadataNative metadata = new CameraMetadataNative();
298             metadata.readFromParcel(in);
299             return metadata;
300         }
301 
302         @Override
303         public CameraMetadataNative[] newArray(int size) {
304             return new CameraMetadataNative[size];
305         }
306     };
307 
308     @Override
describeContents()309     public int describeContents() {
310         return 0;
311     }
312 
313     @Override
writeToParcel(Parcel dest, int flags)314     public void writeToParcel(Parcel dest, int flags) {
315         nativeWriteToParcel(dest);
316     }
317 
318     /**
319      * @hide
320      */
get(CameraCharacteristics.Key<T> key)321     public <T> T get(CameraCharacteristics.Key<T> key) {
322         return get(key.getNativeKey());
323     }
324 
325     /**
326      * @hide
327      */
get(CaptureResult.Key<T> key)328     public <T> T get(CaptureResult.Key<T> key) {
329         return get(key.getNativeKey());
330     }
331 
332     /**
333      * @hide
334      */
get(CaptureRequest.Key<T> key)335     public <T> T get(CaptureRequest.Key<T> key) {
336         return get(key.getNativeKey());
337     }
338 
339     /**
340      * Look-up a metadata field value by its key.
341      *
342      * @param key a non-{@code null} key instance
343      * @return the field corresponding to the {@code key}, or {@code null} if no value was set
344      */
get(Key<T> key)345     public <T> T get(Key<T> key) {
346         Preconditions.checkNotNull(key, "key must not be null");
347 
348         // Check if key has been overridden to use a wrapper class on the java side.
349         GetCommand g = sGetCommandMap.get(key);
350         if (g != null) {
351             return g.getValue(this, key);
352         }
353         return getBase(key);
354     }
355 
readFromParcel(Parcel in)356     public void readFromParcel(Parcel in) {
357         nativeReadFromParcel(in);
358     }
359 
360     /**
361      * Set the global client-side vendor tag descriptor to allow use of vendor
362      * tags in camera applications.
363      *
364      * @return int A native status_t value corresponding to one of the
365      * {@link CameraBinderDecorator} integer constants.
366      * @see CameraBinderDecorator#throwOnError
367      *
368      * @hide
369      */
nativeSetupGlobalVendorTagDescriptor()370     public static native int nativeSetupGlobalVendorTagDescriptor();
371 
372     /**
373      * Set a camera metadata field to a value. The field definitions can be
374      * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
375      * {@link CaptureRequest}.
376      *
377      * @param key The metadata field to write.
378      * @param value The value to set the field to, which must be of a matching
379      * type to the key.
380      */
set(Key<T> key, T value)381     public <T> void set(Key<T> key, T value) {
382         SetCommand s = sSetCommandMap.get(key);
383         if (s != null) {
384             s.setValue(this, value);
385             return;
386         }
387 
388         setBase(key, value);
389     }
390 
set(CaptureRequest.Key<T> key, T value)391     public <T> void set(CaptureRequest.Key<T> key, T value) {
392         set(key.getNativeKey(), value);
393     }
394 
set(CaptureResult.Key<T> key, T value)395     public <T> void set(CaptureResult.Key<T> key, T value) {
396         set(key.getNativeKey(), value);
397     }
398 
set(CameraCharacteristics.Key<T> key, T value)399     public <T> void set(CameraCharacteristics.Key<T> key, T value) {
400         set(key.getNativeKey(), value);
401     }
402 
403     // Keep up-to-date with camera_metadata.h
404     /**
405      * @hide
406      */
407     public static final int TYPE_BYTE = 0;
408     /**
409      * @hide
410      */
411     public static final int TYPE_INT32 = 1;
412     /**
413      * @hide
414      */
415     public static final int TYPE_FLOAT = 2;
416     /**
417      * @hide
418      */
419     public static final int TYPE_INT64 = 3;
420     /**
421      * @hide
422      */
423     public static final int TYPE_DOUBLE = 4;
424     /**
425      * @hide
426      */
427     public static final int TYPE_RATIONAL = 5;
428     /**
429      * @hide
430      */
431     public static final int NUM_TYPES = 6;
432 
close()433     private void close() {
434         // this sets mMetadataPtr to 0
435         nativeClose();
436         mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
437     }
438 
getBase(CameraCharacteristics.Key<T> key)439     private <T> T getBase(CameraCharacteristics.Key<T> key) {
440         return getBase(key.getNativeKey());
441     }
442 
getBase(CaptureResult.Key<T> key)443     private <T> T getBase(CaptureResult.Key<T> key) {
444         return getBase(key.getNativeKey());
445     }
446 
getBase(CaptureRequest.Key<T> key)447     private <T> T getBase(CaptureRequest.Key<T> key) {
448         return getBase(key.getNativeKey());
449     }
450 
getBase(Key<T> key)451     private <T> T getBase(Key<T> key) {
452         int tag = key.getTag();
453         byte[] values = readValues(tag);
454         if (values == null) {
455             return null;
456         }
457 
458         Marshaler<T> marshaler = getMarshalerForKey(key);
459         ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
460         return marshaler.unmarshal(buffer);
461     }
462 
463     // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
464     // metadata.
465     private static final HashMap<Key<?>, GetCommand> sGetCommandMap =
466             new HashMap<Key<?>, GetCommand>();
467     static {
468         sGetCommandMap.put(
GetCommand()469                 CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(), new GetCommand() {
470                     @Override
471                     @SuppressWarnings("unchecked")
472                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
473                         return (T) metadata.getAvailableFormats();
474                     }
475                 });
476         sGetCommandMap.put(
GetCommand()477                 CaptureResult.STATISTICS_FACES.getNativeKey(), new GetCommand() {
478                     @Override
479                     @SuppressWarnings("unchecked")
480                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
481                         return (T) metadata.getFaces();
482                     }
483                 });
484         sGetCommandMap.put(
GetCommand()485                 CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(), new GetCommand() {
486                     @Override
487                     @SuppressWarnings("unchecked")
488                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
489                         return (T) metadata.getFaceRectangles();
490                     }
491                 });
492         sGetCommandMap.put(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey()493                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey(),
494                         new GetCommand() {
495                     @Override
496                     @SuppressWarnings("unchecked")
497                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
498                         return (T) metadata.getStreamConfigurationMap();
499                     }
500                 });
501         sGetCommandMap.put(
CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey()502                 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
503                     @Override
504                     @SuppressWarnings("unchecked")
505                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
506                         return (T) metadata.getMaxRegions(key);
507                     }
508                 });
509         sGetCommandMap.put(
GetCommand()510                 CameraCharacteristics.CONTROL_MAX_REGIONS_AWB.getNativeKey(), new GetCommand() {
511                     @Override
512                     @SuppressWarnings("unchecked")
513                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
514                         return (T) metadata.getMaxRegions(key);
515                     }
516                 });
517         sGetCommandMap.put(
CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey()518                 CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey(), new GetCommand() {
519                     @Override
520                     @SuppressWarnings("unchecked")
521                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
522                         return (T) metadata.getMaxRegions(key);
523                     }
524                 });
525         sGetCommandMap.put(
GetCommand()526                 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW.getNativeKey(), new GetCommand() {
527                     @Override
528                     @SuppressWarnings("unchecked")
529                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
530                         return (T) metadata.getMaxNumOutputs(key);
531                     }
532                 });
533         sGetCommandMap.put(
GetCommand()534                 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC.getNativeKey(), new GetCommand() {
535                     @Override
536                     @SuppressWarnings("unchecked")
537                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
538                         return (T) metadata.getMaxNumOutputs(key);
539                     }
540                 });
541         sGetCommandMap.put(
CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey()542                 CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey(),
543                         new GetCommand() {
544                     @Override
545                     @SuppressWarnings("unchecked")
546                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
547                         return (T) metadata.getMaxNumOutputs(key);
548                     }
549                 });
550         sGetCommandMap.put(
GetCommand()551                 CaptureRequest.TONEMAP_CURVE.getNativeKey(), new GetCommand() {
552                     @Override
553                     @SuppressWarnings("unchecked")
554                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
555                         return (T) metadata.getTonemapCurve();
556                     }
557                 });
558         sGetCommandMap.put(
GetCommand()559                 CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new GetCommand() {
560                     @Override
561                     @SuppressWarnings("unchecked")
562                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
563                         return (T) metadata.getGpsLocation();
564                     }
565                 });
566         sGetCommandMap.put(
CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey()567                 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(),
568                         new GetCommand() {
569                     @Override
570                     @SuppressWarnings("unchecked")
571                     public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
572                         return (T) metadata.getLensShadingMap();
573                     }
574                 });
575     }
576 
getAvailableFormats()577     private int[] getAvailableFormats() {
578         int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
579         if (availableFormats != null) {
580             for (int i = 0; i < availableFormats.length; i++) {
581                 // JPEG has different value between native and managed side, need override.
582                 if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
583                     availableFormats[i] = ImageFormat.JPEG;
584                 }
585             }
586         }
587 
588         return availableFormats;
589     }
590 
setFaces(Face[] faces)591     private boolean setFaces(Face[] faces) {
592         if (faces == null) {
593             return false;
594         }
595 
596         int numFaces = faces.length;
597 
598         // Detect if all faces are SIMPLE or not; count # of valid faces
599         boolean fullMode = true;
600         for (Face face : faces) {
601             if (face == null) {
602                 numFaces--;
603                 Log.w(TAG, "setFaces - null face detected, skipping");
604                 continue;
605             }
606 
607             if (face.getId() == Face.ID_UNSUPPORTED) {
608                 fullMode = false;
609             }
610         }
611 
612         Rect[] faceRectangles = new Rect[numFaces];
613         byte[] faceScores = new byte[numFaces];
614         int[] faceIds = null;
615         int[] faceLandmarks = null;
616 
617         if (fullMode) {
618             faceIds = new int[numFaces];
619             faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
620         }
621 
622         int i = 0;
623         for (Face face : faces) {
624             if (face == null) {
625                 continue;
626             }
627 
628             faceRectangles[i] = face.getBounds();
629             faceScores[i] = (byte)face.getScore();
630 
631             if (fullMode) {
632                 faceIds[i] = face.getId();
633 
634                 int j = 0;
635 
636                 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
637                 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
638                 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
639                 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
640                 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
641                 faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
642             }
643 
644             i++;
645         }
646 
647         set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
648         set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
649         set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
650         set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
651 
652         return true;
653     }
654 
getFaces()655     private Face[] getFaces() {
656         Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
657         byte[] faceScores = get(CaptureResult.STATISTICS_FACE_SCORES);
658         Rect[] faceRectangles = get(CaptureResult.STATISTICS_FACE_RECTANGLES);
659         int[] faceIds = get(CaptureResult.STATISTICS_FACE_IDS);
660         int[] faceLandmarks = get(CaptureResult.STATISTICS_FACE_LANDMARKS);
661 
662         if (areValuesAllNull(faceDetectMode, faceScores, faceRectangles, faceIds, faceLandmarks)) {
663             return null;
664         }
665 
666         if (faceDetectMode == null) {
667             Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
668             faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
669         } else {
670             if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
671                 return new Face[0];
672             }
673             if (faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE &&
674                     faceDetectMode != CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
675                 Log.w(TAG, "Unknown face detect mode: " + faceDetectMode);
676                 return new Face[0];
677             }
678         }
679 
680         // Face scores and rectangles are required by SIMPLE and FULL mode.
681         if (faceScores == null || faceRectangles == null) {
682             Log.w(TAG, "Expect face scores and rectangles to be non-null");
683             return new Face[0];
684         } else if (faceScores.length != faceRectangles.length) {
685             Log.w(TAG, String.format("Face score size(%d) doesn match face rectangle size(%d)!",
686                     faceScores.length, faceRectangles.length));
687         }
688 
689         // To be safe, make number of faces is the minimal of all face info metadata length.
690         int numFaces = Math.min(faceScores.length, faceRectangles.length);
691         // Face id and landmarks are only required by FULL mode.
692         if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
693             if (faceIds == null || faceLandmarks == null) {
694                 Log.w(TAG, "Expect face ids and landmarks to be non-null for FULL mode," +
695                         "fallback to SIMPLE mode");
696                 faceDetectMode = CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE;
697             } else {
698                 if (faceIds.length != numFaces ||
699                         faceLandmarks.length != numFaces * FACE_LANDMARK_SIZE) {
700                     Log.w(TAG, String.format("Face id size(%d), or face landmark size(%d) don't" +
701                             "match face number(%d)!",
702                             faceIds.length, faceLandmarks.length * FACE_LANDMARK_SIZE, numFaces));
703                 }
704                 // To be safe, make number of faces is the minimal of all face info metadata length.
705                 numFaces = Math.min(numFaces, faceIds.length);
706                 numFaces = Math.min(numFaces, faceLandmarks.length / FACE_LANDMARK_SIZE);
707             }
708         }
709 
710         ArrayList<Face> faceList = new ArrayList<Face>();
711         if (faceDetectMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
712             for (int i = 0; i < numFaces; i++) {
713                 if (faceScores[i] <= Face.SCORE_MAX &&
714                         faceScores[i] >= Face.SCORE_MIN) {
715                     faceList.add(new Face(faceRectangles[i], faceScores[i]));
716                 }
717             }
718         } else {
719             // CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL
720             for (int i = 0; i < numFaces; i++) {
721                 if (faceScores[i] <= Face.SCORE_MAX &&
722                         faceScores[i] >= Face.SCORE_MIN &&
723                         faceIds[i] >= 0) {
724                     Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
725                             faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
726                     Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
727                             faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
728                     Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
729                             faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
730                     Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
731                             leftEye, rightEye, mouth);
732                     faceList.add(face);
733                 }
734             }
735         }
736         Face[] faces = new Face[faceList.size()];
737         faceList.toArray(faces);
738         return faces;
739     }
740 
741     // Face rectangles are defined as (left, top, right, bottom) instead of
742     // (left, top, width, height) at the native level, so the normal Rect
743     // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
744     // that conversion here for just the faces.
getFaceRectangles()745     private Rect[] getFaceRectangles() {
746         Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
747         if (faceRectangles == null) return null;
748 
749         Rect[] fixedFaceRectangles = new Rect[faceRectangles.length];
750         for (int i = 0; i < faceRectangles.length; i++) {
751             fixedFaceRectangles[i] = new Rect(
752                     faceRectangles[i].left,
753                     faceRectangles[i].top,
754                     faceRectangles[i].right - faceRectangles[i].left,
755                     faceRectangles[i].bottom - faceRectangles[i].top);
756         }
757         return fixedFaceRectangles;
758     }
759 
getLensShadingMap()760     private LensShadingMap getLensShadingMap() {
761         float[] lsmArray = getBase(CaptureResult.STATISTICS_LENS_SHADING_MAP);
762         Size s = get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE);
763 
764         // Do not warn if lsmArray is null while s is not. This is valid.
765         if (lsmArray == null) {
766             return null;
767         }
768 
769         if (s == null) {
770             Log.w(TAG, "getLensShadingMap - Lens shading map size was null.");
771             return null;
772         }
773 
774         LensShadingMap map = new LensShadingMap(lsmArray, s.getHeight(), s.getWidth());
775         return map;
776     }
777 
getGpsLocation()778     private Location getGpsLocation() {
779         String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
780         double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
781         Long timeStamp = get(CaptureResult.JPEG_GPS_TIMESTAMP);
782 
783         if (areValuesAllNull(processingMethod, coords, timeStamp)) {
784             return null;
785         }
786 
787         Location l = new Location(translateProcessToLocationProvider(processingMethod));
788         if (timeStamp != null) {
789             l.setTime(timeStamp);
790         } else {
791             Log.w(TAG, "getGpsLocation - No timestamp for GPS location.");
792         }
793 
794         if (coords != null) {
795             l.setLatitude(coords[0]);
796             l.setLongitude(coords[1]);
797             l.setAltitude(coords[2]);
798         } else {
799             Log.w(TAG, "getGpsLocation - No coordinates for GPS location");
800         }
801 
802         return l;
803     }
804 
setGpsLocation(Location l)805     private boolean setGpsLocation(Location l) {
806         if (l == null) {
807             return false;
808         }
809 
810         double[] coords = { l.getLatitude(), l.getLongitude(), l.getAltitude() };
811         String processMethod = translateLocationProviderToProcess(l.getProvider());
812         long timestamp = l.getTime();
813 
814         set(CaptureRequest.JPEG_GPS_TIMESTAMP, timestamp);
815         set(CaptureRequest.JPEG_GPS_COORDINATES, coords);
816 
817         if (processMethod == null) {
818             Log.w(TAG, "setGpsLocation - No process method, Location is not from a GPS or NETWORK" +
819                     "provider");
820         } else {
821             setBase(CaptureRequest.JPEG_GPS_PROCESSING_METHOD, processMethod);
822         }
823         return true;
824     }
825 
getStreamConfigurationMap()826     private StreamConfigurationMap getStreamConfigurationMap() {
827         StreamConfiguration[] configurations = getBase(
828                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
829         StreamConfigurationDuration[] minFrameDurations = getBase(
830                 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
831         StreamConfigurationDuration[] stallDurations = getBase(
832                 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
833         HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
834                 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
835 
836         return new StreamConfigurationMap(
837                 configurations, minFrameDurations, stallDurations, highSpeedVideoConfigurations);
838     }
839 
getMaxRegions(Key<T> key)840     private <T> Integer getMaxRegions(Key<T> key) {
841         final int AE = 0;
842         final int AWB = 1;
843         final int AF = 2;
844 
845         // The order of the elements is: (AE, AWB, AF)
846         int[] maxRegions = getBase(CameraCharacteristics.CONTROL_MAX_REGIONS);
847 
848         if (maxRegions == null) {
849             return null;
850         }
851 
852         if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AE)) {
853             return maxRegions[AE];
854         } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB)) {
855             return maxRegions[AWB];
856         } else if (key.equals(CameraCharacteristics.CONTROL_MAX_REGIONS_AF)) {
857             return maxRegions[AF];
858         } else {
859             throw new AssertionError("Invalid key " + key);
860         }
861     }
862 
getMaxNumOutputs(Key<T> key)863     private <T> Integer getMaxNumOutputs(Key<T> key) {
864         final int RAW = 0;
865         final int PROC = 1;
866         final int PROC_STALLING = 2;
867 
868         // The order of the elements is: (raw, proc+nonstalling, proc+stalling)
869         int[] maxNumOutputs = getBase(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS);
870 
871         if (maxNumOutputs == null) {
872             return null;
873         }
874 
875         if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW)) {
876             return maxNumOutputs[RAW];
877         } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC)) {
878             return maxNumOutputs[PROC];
879         } else if (key.equals(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING)) {
880             return maxNumOutputs[PROC_STALLING];
881         } else {
882             throw new AssertionError("Invalid key " + key);
883         }
884     }
885 
getTonemapCurve()886     private <T> TonemapCurve getTonemapCurve() {
887         float[] red = getBase(CaptureRequest.TONEMAP_CURVE_RED);
888         float[] green = getBase(CaptureRequest.TONEMAP_CURVE_GREEN);
889         float[] blue = getBase(CaptureRequest.TONEMAP_CURVE_BLUE);
890 
891         if (areValuesAllNull(red, green, blue)) {
892             return null;
893         }
894 
895         if (red == null || green == null || blue == null) {
896             Log.w(TAG, "getTonemapCurve - missing tone curve components");
897             return null;
898         }
899         TonemapCurve tc = new TonemapCurve(red, green, blue);
900         return tc;
901     }
902 
setBase(CameraCharacteristics.Key<T> key, T value)903     private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
904         setBase(key.getNativeKey(), value);
905     }
906 
setBase(CaptureResult.Key<T> key, T value)907     private <T> void setBase(CaptureResult.Key<T> key, T value) {
908         setBase(key.getNativeKey(), value);
909     }
910 
setBase(CaptureRequest.Key<T> key, T value)911     private <T> void setBase(CaptureRequest.Key<T> key, T value) {
912         setBase(key.getNativeKey(), value);
913     }
914 
setBase(Key<T> key, T value)915     private <T> void setBase(Key<T> key, T value) {
916         int tag = key.getTag();
917 
918         if (value == null) {
919             // Erase the entry
920             writeValues(tag, /*src*/null);
921             return;
922         } // else update the entry to a new value
923 
924         Marshaler<T> marshaler = getMarshalerForKey(key);
925         int size = marshaler.calculateMarshalSize(value);
926 
927         // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
928         byte[] values = new byte[size];
929 
930         ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
931         marshaler.marshal(value, buffer);
932 
933         writeValues(tag, values);
934     }
935 
936     // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden
937     // metadata.
938     private static final HashMap<Key<?>, SetCommand> sSetCommandMap =
939             new HashMap<Key<?>, SetCommand>();
940     static {
CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey()941         sSetCommandMap.put(CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey(),
942                 new SetCommand() {
943             @Override
944             public <T> void setValue(CameraMetadataNative metadata, T value) {
945                 metadata.setAvailableFormats((int[]) value);
946             }
947         });
CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey()948         sSetCommandMap.put(CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey(),
949                 new SetCommand() {
950             @Override
951             public <T> void setValue(CameraMetadataNative metadata, T value) {
952                 metadata.setFaceRectangles((Rect[]) value);
953             }
954         });
CaptureResult.STATISTICS_FACES.getNativeKey()955         sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
956                 new SetCommand() {
957             @Override
958             public <T> void setValue(CameraMetadataNative metadata, T value) {
959                 metadata.setFaces((Face[])value);
960             }
961         });
CaptureRequest.TONEMAP_CURVE.getNativeKey()962         sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
963             @Override
964             public <T> void setValue(CameraMetadataNative metadata, T value) {
965                 metadata.setTonemapCurve((TonemapCurve) value);
966             }
967         });
CaptureResult.JPEG_GPS_LOCATION.getNativeKey()968         sSetCommandMap.put(CaptureResult.JPEG_GPS_LOCATION.getNativeKey(), new SetCommand() {
969             @Override
970             public <T> void setValue(CameraMetadataNative metadata, T value) {
971                 metadata.setGpsLocation((Location) value);
972             }
973         });
974     }
975 
setAvailableFormats(int[] value)976     private boolean setAvailableFormats(int[] value) {
977         int[] availableFormat = value;
978         if (value == null) {
979             // Let setBase() to handle the null value case.
980             return false;
981         }
982 
983         int[] newValues = new int[availableFormat.length];
984         for (int i = 0; i < availableFormat.length; i++) {
985             newValues[i] = availableFormat[i];
986             if (availableFormat[i] == ImageFormat.JPEG) {
987                 newValues[i] = NATIVE_JPEG_FORMAT;
988             }
989         }
990 
991         setBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, newValues);
992         return true;
993     }
994 
995     /**
996      * Convert Face Rectangles from managed side to native side as they have different definitions.
997      * <p>
998      * Managed side face rectangles are defined as: left, top, width, height.
999      * Native side face rectangles are defined as: left, top, right, bottom.
1000      * The input face rectangle need to be converted to native side definition when set is called.
1001      * </p>
1002      *
1003      * @param faceRects Input face rectangles.
1004      * @return true if face rectangles can be set successfully. Otherwise, Let the caller
1005      *             (setBase) to handle it appropriately.
1006      */
setFaceRectangles(Rect[] faceRects)1007     private boolean setFaceRectangles(Rect[] faceRects) {
1008         if (faceRects == null) {
1009             return false;
1010         }
1011 
1012         Rect[] newFaceRects = new Rect[faceRects.length];
1013         for (int i = 0; i < newFaceRects.length; i++) {
1014             newFaceRects[i] = new Rect(
1015                     faceRects[i].left,
1016                     faceRects[i].top,
1017                     faceRects[i].right + faceRects[i].left,
1018                     faceRects[i].bottom + faceRects[i].top);
1019         }
1020 
1021         setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
1022         return true;
1023     }
1024 
setTonemapCurve(TonemapCurve tc)1025     private <T> boolean setTonemapCurve(TonemapCurve tc) {
1026         if (tc == null) {
1027             return false;
1028         }
1029 
1030         float[][] curve = new float[3][];
1031         for (int i = TonemapCurve.CHANNEL_RED; i <= TonemapCurve.CHANNEL_BLUE; i++) {
1032             int pointCount = tc.getPointCount(i);
1033             curve[i] = new float[pointCount * TonemapCurve.POINT_SIZE];
1034             tc.copyColorCurve(i, curve[i], 0);
1035         }
1036         setBase(CaptureRequest.TONEMAP_CURVE_RED, curve[0]);
1037         setBase(CaptureRequest.TONEMAP_CURVE_GREEN, curve[1]);
1038         setBase(CaptureRequest.TONEMAP_CURVE_BLUE, curve[2]);
1039 
1040         return true;
1041     }
1042 
1043     private long mMetadataPtr; // native CameraMetadata*
1044 
nativeAllocate()1045     private native long nativeAllocate();
nativeAllocateCopy(CameraMetadataNative other)1046     private native long nativeAllocateCopy(CameraMetadataNative other)
1047             throws NullPointerException;
1048 
nativeWriteToParcel(Parcel dest)1049     private native synchronized void nativeWriteToParcel(Parcel dest);
nativeReadFromParcel(Parcel source)1050     private native synchronized void nativeReadFromParcel(Parcel source);
nativeSwap(CameraMetadataNative other)1051     private native synchronized void nativeSwap(CameraMetadataNative other)
1052             throws NullPointerException;
nativeClose()1053     private native synchronized void nativeClose();
nativeIsEmpty()1054     private native synchronized boolean nativeIsEmpty();
nativeGetEntryCount()1055     private native synchronized int nativeGetEntryCount();
1056 
nativeReadValues(int tag)1057     private native synchronized byte[] nativeReadValues(int tag);
nativeWriteValues(int tag, byte[] src)1058     private native synchronized void nativeWriteValues(int tag, byte[] src);
nativeDump()1059     private native synchronized void nativeDump() throws IOException; // dump to ALOGD
1060 
nativeGetTagFromKey(String keyName)1061     private static native int nativeGetTagFromKey(String keyName)
1062             throws IllegalArgumentException;
nativeGetTypeFromTag(int tag)1063     private static native int nativeGetTypeFromTag(int tag)
1064             throws IllegalArgumentException;
nativeClassInit()1065     private static native void nativeClassInit();
1066 
1067     /**
1068      * <p>Perform a 0-copy swap of the internal metadata with another object.</p>
1069      *
1070      * <p>Useful to convert a CameraMetadata into e.g. a CaptureRequest.</p>
1071      *
1072      * @param other Metadata to swap with
1073      * @throws NullPointerException if other was null
1074      * @hide
1075      */
swap(CameraMetadataNative other)1076     public void swap(CameraMetadataNative other) {
1077         nativeSwap(other);
1078     }
1079 
1080     /**
1081      * @hide
1082      */
getEntryCount()1083     public int getEntryCount() {
1084         return nativeGetEntryCount();
1085     }
1086 
1087     /**
1088      * Does this metadata contain at least 1 entry?
1089      *
1090      * @hide
1091      */
isEmpty()1092     public boolean isEmpty() {
1093         return nativeIsEmpty();
1094     }
1095 
1096     /**
1097      * Convert a key string into the equivalent native tag.
1098      *
1099      * @throws IllegalArgumentException if the key was not recognized
1100      * @throws NullPointerException if the key was null
1101      *
1102      * @hide
1103      */
getTag(String key)1104     public static int getTag(String key) {
1105         return nativeGetTagFromKey(key);
1106     }
1107 
1108     /**
1109      * Get the underlying native type for a tag.
1110      *
1111      * @param tag An integer tag, see e.g. {@link #getTag}
1112      * @return An int enum for the metadata type, see e.g. {@link #TYPE_BYTE}
1113      *
1114      * @hide
1115      */
getNativeType(int tag)1116     public static int getNativeType(int tag) {
1117         return nativeGetTypeFromTag(tag);
1118     }
1119 
1120     /**
1121      * <p>Updates the existing entry for tag with the new bytes pointed by src, erasing
1122      * the entry if src was null.</p>
1123      *
1124      * <p>An empty array can be passed in to update the entry to 0 elements.</p>
1125      *
1126      * @param tag An integer tag, see e.g. {@link #getTag}
1127      * @param src An array of bytes, or null to erase the entry
1128      *
1129      * @hide
1130      */
writeValues(int tag, byte[] src)1131     public void writeValues(int tag, byte[] src) {
1132         nativeWriteValues(tag, src);
1133     }
1134 
1135     /**
1136      * <p>Returns a byte[] of data corresponding to this tag. Use a wrapped bytebuffer to unserialize
1137      * the data properly.</p>
1138      *
1139      * <p>An empty array can be returned to denote an existing entry with 0 elements.</p>
1140      *
1141      * @param tag An integer tag, see e.g. {@link #getTag}
1142      *
1143      * @return {@code null} if there were 0 entries for this tag, a byte[] otherwise.
1144      * @hide
1145      */
readValues(int tag)1146     public byte[] readValues(int tag) {
1147         // TODO: Optimization. Native code returns a ByteBuffer instead.
1148         return nativeReadValues(tag);
1149     }
1150 
1151     /**
1152      * Dumps the native metadata contents to logcat.
1153      *
1154      * <p>Visibility for testing/debugging only. The results will not
1155      * include any synthesized keys, as they are invisible to the native layer.</p>
1156      *
1157      * @hide
1158      */
dumpToLog()1159     public void dumpToLog() {
1160         try {
1161             nativeDump();
1162         } catch (IOException e) {
1163             Log.wtf(TAG, "Dump logging failed", e);
1164         }
1165     }
1166 
1167     @Override
finalize()1168     protected void finalize() throws Throwable {
1169         try {
1170             close();
1171         } finally {
1172             super.finalize();
1173         }
1174     }
1175 
1176     /**
1177      * Get the marshaler compatible with the {@code key} and type {@code T}.
1178      *
1179      * @throws UnsupportedOperationException
1180      *          if the native/managed type combination for {@code key} is not supported
1181      */
getMarshalerForKey(Key<T> key)1182     private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
1183         return MarshalRegistry.getMarshaler(key.getTypeReference(),
1184                 getNativeType(key.getTag()));
1185     }
1186 
1187     @SuppressWarnings({ "unchecked", "rawtypes" })
registerAllMarshalers()1188     private static void registerAllMarshalers() {
1189         if (VERBOSE) {
1190             Log.v(TAG, "Shall register metadata marshalers");
1191         }
1192 
1193         MarshalQueryable[] queryList = new MarshalQueryable[] {
1194                 // marshalers for standard types
1195                 new MarshalQueryablePrimitive(),
1196                 new MarshalQueryableEnum(),
1197                 new MarshalQueryableArray(),
1198 
1199                 // pseudo standard types, that expand/narrow the native type into a managed type
1200                 new MarshalQueryableBoolean(),
1201                 new MarshalQueryableNativeByteToInteger(),
1202 
1203                 // marshalers for custom types
1204                 new MarshalQueryableRect(),
1205                 new MarshalQueryableSize(),
1206                 new MarshalQueryableSizeF(),
1207                 new MarshalQueryableString(),
1208                 new MarshalQueryableReprocessFormatsMap(),
1209                 new MarshalQueryableRange(),
1210                 new MarshalQueryablePair(),
1211                 new MarshalQueryableMeteringRectangle(),
1212                 new MarshalQueryableColorSpaceTransform(),
1213                 new MarshalQueryableStreamConfiguration(),
1214                 new MarshalQueryableStreamConfigurationDuration(),
1215                 new MarshalQueryableRggbChannelVector(),
1216                 new MarshalQueryableBlackLevelPattern(),
1217                 new MarshalQueryableHighSpeedVideoConfiguration(),
1218 
1219                 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
1220                 new MarshalQueryableParcelable(),
1221         };
1222 
1223         for (MarshalQueryable query : queryList) {
1224             MarshalRegistry.registerMarshalQueryable(query);
1225         }
1226         if (VERBOSE) {
1227             Log.v(TAG, "Registered metadata marshalers");
1228         }
1229     }
1230 
1231     /** Check if input arguments are all {@code null}.
1232      *
1233      * @param objs Input arguments for null check
1234      * @return {@code true} if input arguments are all {@code null}, otherwise {@code false}
1235      */
areValuesAllNull(Object... objs)1236     private static boolean areValuesAllNull(Object... objs) {
1237         for (Object o : objs) {
1238             if (o != null) return false;
1239         }
1240         return true;
1241     }
1242 
1243     static {
1244         /*
1245          * We use a class initializer to allow the native code to cache some field offsets
1246          */
nativeClassInit()1247         nativeClassInit();
registerAllMarshalers()1248         registerAllMarshalers();
1249     }
1250 }
1251