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