Home | History | Annotate | Download | only in impl
      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          */
     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")
    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          */
    134         public final String getName() {
    135             return mName;
    136         }
    137 
    138         /**
    139          * {@inheritDoc}
    140          */
    141         @Override
    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
    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          */
    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          */
    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          */
    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 
    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 
    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 
    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      */
    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      */
    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
    309     public int describeContents() {
    310         return 0;
    311     }
    312 
    313     @Override
    314     public void writeToParcel(Parcel dest, int flags) {
    315         nativeWriteToParcel(dest);
    316     }
    317 
    318     /**
    319      * @hide
    320      */
    321     public <T> T get(CameraCharacteristics.Key<T> key) {
    322         return get(key.getNativeKey());
    323     }
    324 
    325     /**
    326      * @hide
    327      */
    328     public <T> T get(CaptureResult.Key<T> key) {
    329         return get(key.getNativeKey());
    330     }
    331 
    332     /**
    333      * @hide
    334      */
    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      */
    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 
    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      */
    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      */
    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 
    391     public <T> void set(CaptureRequest.Key<T> key, T value) {
    392         set(key.getNativeKey(), value);
    393     }
    394 
    395     public <T> void set(CaptureResult.Key<T> key, T value) {
    396         set(key.getNativeKey(), value);
    397     }
    398 
    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 
    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 
    439     private <T> T getBase(CameraCharacteristics.Key<T> key) {
    440         return getBase(key.getNativeKey());
    441     }
    442 
    443     private <T> T getBase(CaptureResult.Key<T> key) {
    444         return getBase(key.getNativeKey());
    445     }
    446 
    447     private <T> T getBase(CaptureRequest.Key<T> key) {
    448         return getBase(key.getNativeKey());
    449     }
    450 
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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(
    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 
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    903     private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
    904         setBase(key.getNativeKey(), value);
    905     }
    906 
    907     private <T> void setBase(CaptureResult.Key<T> key, T value) {
    908         setBase(key.getNativeKey(), value);
    909     }
    910 
    911     private <T> void setBase(CaptureRequest.Key<T> key, T value) {
    912         setBase(key.getNativeKey(), value);
    913     }
    914 
    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 {
    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         });
    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         });
    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         });
    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         });
    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 
    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      */
   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 
   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 
   1045     private native long nativeAllocate();
   1046     private native long nativeAllocateCopy(CameraMetadataNative other)
   1047             throws NullPointerException;
   1048 
   1049     private native synchronized void nativeWriteToParcel(Parcel dest);
   1050     private native synchronized void nativeReadFromParcel(Parcel source);
   1051     private native synchronized void nativeSwap(CameraMetadataNative other)
   1052             throws NullPointerException;
   1053     private native synchronized void nativeClose();
   1054     private native synchronized boolean nativeIsEmpty();
   1055     private native synchronized int nativeGetEntryCount();
   1056 
   1057     private native synchronized byte[] nativeReadValues(int tag);
   1058     private native synchronized void nativeWriteValues(int tag, byte[] src);
   1059     private native synchronized void nativeDump() throws IOException; // dump to ALOGD
   1060 
   1061     private static native int nativeGetTagFromKey(String keyName)
   1062             throws IllegalArgumentException;
   1063     private static native int nativeGetTypeFromTag(int tag)
   1064             throws IllegalArgumentException;
   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      */
   1076     public void swap(CameraMetadataNative other) {
   1077         nativeSwap(other);
   1078     }
   1079 
   1080     /**
   1081      * @hide
   1082      */
   1083     public int getEntryCount() {
   1084         return nativeGetEntryCount();
   1085     }
   1086 
   1087     /**
   1088      * Does this metadata contain at least 1 entry?
   1089      *
   1090      * @hide
   1091      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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
   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      */
   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" })
   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      */
   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          */
   1247         nativeClassInit();
   1248         registerAllMarshalers();
   1249     }
   1250 }
   1251