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