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