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