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          */
Key(String name, Class<T> type, long vendorId)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          */
Key(String name, String fallbackName, Class<T> type)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          */
Key(String name, Class<T> type)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")
Key(String name, TypeReference<T> typeReference)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          */
getName()175         public final String getName() {
176             return mName;
177         }
178 
179         /**
180          * {@inheritDoc}
181          */
182         @Override
hashCode()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
equals(Object o)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          */
getTag()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          */
getType()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          */
getVendorId()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          */
getTypeReference()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 
translateLocationProviderToProcess(final String provider)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 
translateProcessToLocationProvider(final String process)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 
CameraMetadataNative()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      */
CameraMetadataNative(CameraMetadataNative other)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      */
move(CameraMetadataNative other)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
describeContents()360     public int describeContents() {
361         return 0;
362     }
363 
364     @Override
writeToParcel(Parcel dest, int flags)365     public void writeToParcel(Parcel dest, int flags) {
366         nativeWriteToParcel(dest);
367     }
368 
369     /**
370      * @hide
371      */
get(CameraCharacteristics.Key<T> key)372     public <T> T get(CameraCharacteristics.Key<T> key) {
373         return get(key.getNativeKey());
374     }
375 
376     /**
377      * @hide
378      */
get(CaptureResult.Key<T> key)379     public <T> T get(CaptureResult.Key<T> key) {
380         return get(key.getNativeKey());
381     }
382 
383     /**
384      * @hide
385      */
get(CaptureRequest.Key<T> key)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      */
get(Key<T> key)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 
readFromParcel(Parcel in)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      */
setupGlobalVendorTagDescriptor()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      */
nativeSetupGlobalVendorTagDescriptor()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      */
set(Key<T> key, T value)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 
set(CaptureRequest.Key<T> key, T value)453     public <T> void set(CaptureRequest.Key<T> key, T value) {
454         set(key.getNativeKey(), value);
455     }
456 
set(CaptureResult.Key<T> key, T value)457     public <T> void set(CaptureResult.Key<T> key, T value) {
458         set(key.getNativeKey(), value);
459     }
460 
set(CameraCharacteristics.Key<T> key, T value)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 
close()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 
getBase(CameraCharacteristics.Key<T> key)501     private <T> T getBase(CameraCharacteristics.Key<T> key) {
502         return getBase(key.getNativeKey());
503     }
504 
getBase(CaptureResult.Key<T> key)505     private <T> T getBase(CaptureResult.Key<T> key) {
506         return getBase(key.getNativeKey());
507     }
508 
getBase(CaptureRequest.Key<T> key)509     private <T> T getBase(CaptureRequest.Key<T> key) {
510         return getBase(key.getNativeKey());
511     }
512 
getBase(Key<T> key)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(
GetCommand()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(
GetCommand()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(
GetCommand()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(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP.getNativeKey()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(
CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey()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(
GetCommand()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(
CameraCharacteristics.CONTROL_MAX_REGIONS_AF.getNativeKey()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(
GetCommand()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(
GetCommand()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(
CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING.getNativeKey()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(
GetCommand()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(
GetCommand()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(
CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey()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(
CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey()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 
getAvailableFormats()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 
setFaces(Face[] faces)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 
getFaces()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.
getFaceRectangles()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 
getLensShadingMap()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 
getGpsLocation()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 
setGpsLocation(Location l)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 
getStreamConfigurationMap()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 
getMaxRegions(Key<T> key)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 
getMaxNumOutputs(Key<T> key)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 
getTonemapCurve()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 
getOisSamples()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 
setBase(CameraCharacteristics.Key<T> key, T value)1048     private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
1049         setBase(key.getNativeKey(), value);
1050     }
1051 
setBase(CaptureResult.Key<T> key, T value)1052     private <T> void setBase(CaptureResult.Key<T> key, T value) {
1053         setBase(key.getNativeKey(), value);
1054     }
1055 
setBase(CaptureRequest.Key<T> key, T value)1056     private <T> void setBase(CaptureRequest.Key<T> key, T value) {
1057         setBase(key.getNativeKey(), value);
1058     }
1059 
setBase(Key<T> key, T value)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 {
CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey()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         });
CaptureResult.STATISTICS_FACE_RECTANGLES.getNativeKey()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         });
CaptureResult.STATISTICS_FACES.getNativeKey()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         });
CaptureRequest.TONEMAP_CURVE.getNativeKey()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         });
CaptureResult.JPEG_GPS_LOCATION.getNativeKey()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 
setAvailableFormats(int[] value)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      */
setFaceRectangles(Rect[] faceRects)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 
setTonemapCurve(TonemapCurve tc)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 
nativeAllocate()1190     private native long nativeAllocate();
nativeAllocateCopy(CameraMetadataNative other)1191     private native long nativeAllocateCopy(CameraMetadataNative other)
1192             throws NullPointerException;
1193 
nativeWriteToParcel(Parcel dest)1194     private native synchronized void nativeWriteToParcel(Parcel dest);
nativeReadFromParcel(Parcel source)1195     private native synchronized void nativeReadFromParcel(Parcel source);
nativeSwap(CameraMetadataNative other)1196     private native synchronized void nativeSwap(CameraMetadataNative other)
1197             throws NullPointerException;
nativeClose()1198     private native synchronized void nativeClose();
nativeIsEmpty()1199     private native synchronized boolean nativeIsEmpty();
nativeGetEntryCount()1200     private native synchronized int nativeGetEntryCount();
1201 
nativeReadValues(int tag)1202     private native synchronized byte[] nativeReadValues(int tag);
nativeWriteValues(int tag, byte[] src)1203     private native synchronized void nativeWriteValues(int tag, byte[] src);
nativeDump()1204     private native synchronized void nativeDump() throws IOException; // dump to ALOGD
1205 
nativeGetAllVendorKeys(Class keyClass)1206     private native synchronized ArrayList nativeGetAllVendorKeys(Class keyClass);
nativeGetTagFromKeyLocal(String keyName)1207     private native synchronized int nativeGetTagFromKeyLocal(String keyName)
1208             throws IllegalArgumentException;
nativeGetTypeFromTagLocal(int tag)1209     private native synchronized int nativeGetTypeFromTagLocal(int tag)
1210             throws IllegalArgumentException;
nativeGetTagFromKey(String keyName, long vendorId)1211     private static native int nativeGetTagFromKey(String keyName, long vendorId)
1212             throws IllegalArgumentException;
nativeGetTypeFromTag(int tag, long vendorId)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      */
swap(CameraMetadataNative other)1225     public void swap(CameraMetadataNative other) {
1226         nativeSwap(other);
1227     }
1228 
1229     /**
1230      * @hide
1231      */
getEntryCount()1232     public int getEntryCount() {
1233         return nativeGetEntryCount();
1234     }
1235 
1236     /**
1237      * Does this metadata contain at least 1 entry?
1238      *
1239      * @hide
1240      */
isEmpty()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      */
getAllVendorKeys(Class<K> keyClass)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      */
getTag(String key)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      */
getTag(String key, long vendorId)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      */
getNativeType(int tag, long vendorId)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      */
writeValues(int tag, byte[] src)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      */
readValues(int tag)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      */
dumpToLog()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
finalize()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      */
getMarshalerForKey(Key<T> key, int nativeType)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" })
registerAllMarshalers()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      */
areValuesAllNull(Object... objs)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 {
registerAllMarshalers()1419         registerAllMarshalers();
1420     }
1421 }
1422