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