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 com.android.mediaframeworktest.unit;
18 
19 import android.test.suitebuilder.annotation.SmallTest;
20 import android.util.Log;
21 import android.util.Pair;
22 import android.util.Range;
23 import android.util.Rational;
24 import android.util.SizeF;
25 import android.graphics.ImageFormat;
26 import android.graphics.Point;
27 import android.graphics.PointF;
28 import android.graphics.Rect;
29 import android.graphics.SurfaceTexture;
30 import android.hardware.camera2.CameraCharacteristics;
31 import android.hardware.camera2.CameraMetadata;
32 import android.hardware.camera2.CaptureRequest;
33 import android.hardware.camera2.CaptureResult;
34 import android.util.Size;
35 import android.hardware.camera2.impl.CameraMetadataNative;
36 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
37 import android.hardware.camera2.params.ColorSpaceTransform;
38 import android.hardware.camera2.params.Face;
39 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
40 import android.hardware.camera2.params.MeteringRectangle;
41 import android.hardware.camera2.params.ReprocessFormatsMap;
42 import android.hardware.camera2.params.RggbChannelVector;
43 import android.hardware.camera2.params.StreamConfiguration;
44 import android.hardware.camera2.params.StreamConfigurationDuration;
45 import android.hardware.camera2.params.StreamConfigurationMap;
46 import android.hardware.camera2.params.TonemapCurve;
47 import android.hardware.camera2.utils.TypeReference;
48 
49 import static android.hardware.camera2.impl.CameraMetadataNative.*;
50 import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*;
51 
52 import java.lang.reflect.Array;
53 import java.nio.ByteBuffer;
54 import java.nio.ByteOrder;
55 import java.util.List;
56 
57 /**
58  * <pre>
59  * adb shell am instrument \
60  *      -e class 'com.android.mediaframeworktest.unit.CameraMetadataTest' \
61  *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
62  * </pre>
63  */
64 public class CameraMetadataTest extends junit.framework.TestCase {
65 
66     private static final boolean VERBOSE = false;
67     private static final String TAG = "CameraMetadataTest";
68 
69 
70     CameraMetadataNative mMetadata;
71 
72     // Sections
73     static final int ANDROID_COLOR_CORRECTION = 0;
74     static final int ANDROID_CONTROL = 1;
75 
76     // Section starts
77     static final int ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16;
78     static final int ANDROID_CONTROL_START = ANDROID_CONTROL << 16;
79 
80     // Tags
81     static final int ANDROID_COLOR_CORRECTION_MODE = ANDROID_COLOR_CORRECTION_START;
82     static final int ANDROID_COLOR_CORRECTION_TRANSFORM = ANDROID_COLOR_CORRECTION_START + 1;
83     static final int ANDROID_COLOR_CORRECTION_GAINS = ANDROID_COLOR_CORRECTION_START + 2;
84 
85     static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START;
86     static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1;
87 
88     // From graphics.h
89     private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
90 
91     @Override
setUp()92     public void setUp() {
93         mMetadata = new CameraMetadataNative();
94     }
95 
96     @Override
tearDown()97     public void tearDown() throws Exception {
98         mMetadata = null;
99     }
100 
101     @SmallTest
testNew()102     public void testNew() {
103         assertEquals(0, mMetadata.getEntryCount());
104         assertTrue(mMetadata.isEmpty());
105     }
106 
107     @SmallTest
testGetTagFromKey()108     public void testGetTagFromKey() {
109 
110         // Test success
111 
112         assertEquals(ANDROID_COLOR_CORRECTION_MODE,
113                 CameraMetadataNative.getTag("android.colorCorrection.mode"));
114         assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM,
115                 CameraMetadataNative.getTag("android.colorCorrection.transform"));
116         assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
117                 CameraMetadataNative.getTag("android.control.aeAntibandingMode"));
118         assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
119                 CameraMetadataNative.getTag("android.control.aeExposureCompensation"));
120 
121         // Test failures
122 
123         try {
124             CameraMetadataNative.getTag(null);
125             fail("A null key should throw NPE");
126         } catch(NullPointerException e) {
127         }
128 
129         try {
130             CameraMetadataNative.getTag("android.control");
131             fail("A section name only should not be a valid key");
132         } catch(IllegalArgumentException e) {
133         }
134 
135         try {
136             CameraMetadataNative.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
137             fail("A valid section with an invalid tag name should not be a valid key");
138         } catch(IllegalArgumentException e) {
139         }
140 
141         try {
142             CameraMetadataNative.getTag("android");
143             fail("A namespace name only should not be a valid key");
144         } catch(IllegalArgumentException e) {
145         }
146 
147         try {
148             CameraMetadataNative.getTag("this.key.is.definitely.invalid");
149             fail("A completely fake key name should not be valid");
150         } catch(IllegalArgumentException e) {
151         }
152     }
153 
154     @SmallTest
testGetTypeFromTag()155     public void testGetTypeFromTag() {
156         assertEquals(TYPE_BYTE,
157                 CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE, Long.MAX_VALUE));
158         assertEquals(TYPE_RATIONAL,
159                 CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM, Long.MAX_VALUE));
160         assertEquals(TYPE_FLOAT,
161                 CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS, Long.MAX_VALUE));
162         assertEquals(TYPE_BYTE,
163                 CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE, Long.MAX_VALUE));
164         assertEquals(TYPE_INT32,
165                 CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, Long.MAX_VALUE));
166 
167         try {
168             CameraMetadataNative.getNativeType(0xDEADF00D, Long.MAX_VALUE);
169             fail("No type should exist for invalid tag 0xDEADF00D");
170         } catch(IllegalArgumentException e) {
171         }
172     }
173 
174     @SmallTest
testReadWriteValues()175     public void testReadWriteValues() {
176         final byte ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
177         byte[] valueResult;
178 
179         assertEquals(0, mMetadata.getEntryCount());
180         assertEquals(true, mMetadata.isEmpty());
181 
182         //
183         // android.colorCorrection.mode (single enum byte)
184         //
185 
186         assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
187 
188         // Write/read null values
189         mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, null);
190         assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
191 
192         // Write 0 values
193         mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {});
194 
195         // Read 0 values
196         valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
197         assertNotNull(valueResult);
198         assertEquals(0, valueResult.length);
199 
200         assertEquals(1, mMetadata.getEntryCount());
201         assertEquals(false, mMetadata.isEmpty());
202 
203         // Write 1 value
204         mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {
205             ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY
206         });
207 
208         // Read 1 value
209         valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
210         assertNotNull(valueResult);
211         assertEquals(1, valueResult.length);
212         assertEquals(ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY, valueResult[0]);
213 
214         assertEquals(1, mMetadata.getEntryCount());
215         assertEquals(false, mMetadata.isEmpty());
216 
217         //
218         // android.colorCorrection.colorCorrectionGains (float x 4 array)
219         //
220 
221         final float[] colorCorrectionGains = new float[] { 1.0f, 2.0f, 3.0f, 4.0f};
222         byte[] colorCorrectionGainsAsByteArray = new byte[colorCorrectionGains.length * 4];
223         ByteBuffer colorCorrectionGainsByteBuffer =
224                 ByteBuffer.wrap(colorCorrectionGainsAsByteArray).order(ByteOrder.nativeOrder());
225         for (float f : colorCorrectionGains)
226             colorCorrectionGainsByteBuffer.putFloat(f);
227 
228         // Read
229         assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS));
230         mMetadata.writeValues(ANDROID_COLOR_CORRECTION_GAINS, colorCorrectionGainsAsByteArray);
231 
232         // Write
233         assertArrayEquals(colorCorrectionGainsAsByteArray,
234                 mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS));
235 
236         assertEquals(2, mMetadata.getEntryCount());
237         assertEquals(false, mMetadata.isEmpty());
238 
239         // Erase
240         mMetadata.writeValues(ANDROID_COLOR_CORRECTION_GAINS, null);
241         assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS));
242         assertEquals(1, mMetadata.getEntryCount());
243     }
244 
245     /**
246      * Format an array into a string with the {@code badIndex} highlighted with {@code **}.
247      *
248      * <p>Numbers are printed as hexadecimal values.</p>
249      *
250      * <p>Example: {@code "[hello, **world**]"} for a {@code string[]},
251      * or a {@code "[**0xFF**, 0xFF]"} for a {@code int[]}.</p>
252      */
formatArray(T array, int badIndex)253     private static <T> String formatArray(T array, int badIndex) {
254         StringBuilder builder = new StringBuilder();
255 
256         builder.append("[");
257 
258         int len = Array.getLength(array);
259         for (int i = 0; i < len; ++i) {
260 
261             Object elem = Array.get(array, i);
262 
263             if (i == badIndex) {
264                 builder.append("**");
265             }
266 
267             if (elem instanceof Byte) {
268                 builder.append(String.format("%x", (Byte) elem));
269             } else if (elem instanceof Short) {
270                 builder.append(String.format("%x", (Short) elem));
271             } else if (elem instanceof Integer) {
272                 builder.append(String.format("%x", (Integer) elem));
273             } else if (elem instanceof Long) {
274                 builder.append(String.format("%x", (Long) elem));
275             } else {
276                 builder.append(elem);
277             }
278 
279             if (i == badIndex) {
280                 builder.append("**");
281             }
282 
283             if (i != len - 1) {
284                 builder.append(", ");
285             }
286         }
287 
288         builder.append("]");
289 
290         return builder.toString();
291     }
292 
assertArrayEquals(T expected, T actual)293     private static <T> void assertArrayEquals(T expected, T actual) {
294         if (!expected.getClass().isArray() || !actual.getClass().isArray()) {
295             throw new IllegalArgumentException("expected, actual must both be arrays");
296         }
297 
298         assertEquals("Array lengths must be equal",
299                 Array.getLength(expected), Array.getLength(actual));
300 
301         int len = Array.getLength(expected);
302         for (int i = 0; i < len; ++i) {
303 
304             Object expectedElement = Array.get(expected, i);
305             Object actualElement = Array.get(actual, i);
306 
307             if (!expectedElement.equals(actualElement)) {
308                 fail(String.format(
309                         "element %d in array was not equal (expected %s, actual %s). "
310                                 + "Arrays were: (expected %s, actual %s).",
311                                 i, expectedElement, actualElement,
312                                 formatArray(expected, i),
313                                 formatArray(actual, i)));
314             }
315         }
316     }
317 
assertArrayContains(T needle, T2 array)318     private static <T, T2> void assertArrayContains(T needle, T2 array) {
319         if (!array.getClass().isArray()) {
320             throw new IllegalArgumentException("actual must be array");
321         }
322 
323         int len = Array.getLength(array);
324         for (int i = 0; i < len; ++i) {
325 
326             Object actualElement = Array.get(array, i);
327 
328             if (needle.equals(actualElement)) {
329                 return;
330             }
331         }
332 
333         fail(String.format(
334                 "could not find element in array (needle %s). "
335                         + "Array was: %s.",
336                         needle,
337                         formatArray(array, len)));
338     }
339 
checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected, boolean reuse)340     private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected,
341             boolean reuse) {
342         Key<T> key = new Key<T>(keyStr, typeToken);
343         assertNull(mMetadata.get(key));
344         mMetadata.set(key, null);
345         assertNull(mMetadata.get(key));
346         mMetadata.set(key, expected);
347 
348         T actual = mMetadata.get(key);
349 
350         if (typeToken.getRawType().isArray()) {
351             assertArrayEquals(expected, actual);
352         } else {
353             assertEquals(expected, actual);
354         }
355 
356         if (reuse) {
357             // reset the key incase we want to use it again
358             mMetadata.set(key, null);
359         }
360     }
361 
checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected)362     private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected) {
363         checkKeyGetAndSet(keyStr, typeToken, expected, /*reuse*/false);
364     }
365 
checkKeyGetAndSet(String keyStr, Class<T> type, T expected)366     private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T expected) {
367         checkKeyGetAndSet(keyStr, TypeReference.createSpecializedTypeReference(type), expected);
368     }
369 
370     /**
371      * Ensure that the data survives a marshal/unmarshal round-trip;
372      * it must also be equal to the {@code expectedNative} byte array.
373      *
374      * <p>As a side-effect, the metadata value corresponding to the key is now set to
375      * {@code expected}.</p>
376      *
377      * @return key created with {@code keyName} and {@code T}
378      */
checkKeyMarshal(String keyName, TypeReference<T> typeReference, T expected, byte[] expectedNative)379     private <T> Key<T> checkKeyMarshal(String keyName, TypeReference<T> typeReference,
380             T expected, byte[] expectedNative) {
381         Key<T> key = new Key<T>(keyName, typeReference);
382 
383         mMetadata.set(key, null);
384         assertNull(mMetadata.get(key));
385 
386         // Write managed value -> make sure native bytes are what we expect
387         mMetadata.set(key, expected);
388 
389         byte[] actualValues = mMetadata.readValues(key.getTag());
390         assertArrayEquals(expectedNative, actualValues);
391 
392         // Write managed value -> make sure read-out managed value is what we expect
393         T actual = mMetadata.get(key);
394 
395         if (typeReference.getRawType().isArray()) {
396             assertArrayEquals(expected, actual);
397         } else {
398             assertEquals(expected, actual);
399         }
400 
401         // Write native bytes -> make sure read-out managed value is what we expect
402         mMetadata.writeValues(key.getTag(), expectedNative);
403         actual = mMetadata.get(key);
404 
405         if (typeReference.getRawType().isArray()) {
406             assertArrayEquals(expected, actual);
407         } else {
408             assertEquals(expected, actual);
409         }
410 
411         return key;
412     }
413 
414     /**
415      * Ensure that the data survives a marshal/unmarshal round-trip;
416      * it must also be equal to the {@code expectedNative} byte array.
417      *
418      * <p>As a side-effect,
419      * the metadata value corresponding to the key is now set to {@code expected}.</p>
420      *
421      * @return key created with {@code keyName} and {@code T}
422      */
checkKeyMarshal(String keyName, T expected, byte[] expectedNative)423     private <T> Key<T> checkKeyMarshal(String keyName, T expected, byte[] expectedNative) {
424         @SuppressWarnings("unchecked")
425         Class<T> expectedClass = (Class<T>) expected.getClass();
426         return checkKeyMarshal(keyName,
427                 TypeReference.createSpecializedTypeReference(expectedClass),
428                 expected,
429                 expectedNative);
430     }
431 
432     @SmallTest
testReadWritePrimitive()433     public void testReadWritePrimitive() {
434         // int32 (single)
435         checkKeyGetAndSet("android.control.aeExposureCompensation", Integer.TYPE, 0xC0FFEE);
436 
437         // byte (single)
438         checkKeyGetAndSet("android.flash.maxEnergy", Byte.TYPE, (byte)6);
439 
440         // int64 (single)
441         checkKeyGetAndSet("android.flash.firingTime", Long.TYPE, 0xABCD12345678FFFFL);
442 
443         // float (single)
444         checkKeyGetAndSet("android.lens.aperture", Float.TYPE, Float.MAX_VALUE);
445 
446         // double (single) -- technically double x 3, but we fake it
447         checkKeyGetAndSet("android.jpeg.gpsCoordinates", Double.TYPE, Double.MAX_VALUE);
448 
449         // rational (single)
450         checkKeyGetAndSet("android.sensor.baseGainFactor", Rational.class, new Rational(1, 2));
451 
452         /**
453          * Weirder cases, that don't map 1:1 with the native types
454          */
455 
456         // bool (single) -- with TYPE_BYTE
457         checkKeyGetAndSet("android.control.aeLock", Boolean.TYPE, true);
458 
459         // integer (single) -- with TYPE_BYTE
460         checkKeyGetAndSet("android.control.aePrecaptureTrigger", Integer.TYPE, 6);
461     }
462 
463     @SmallTest
testReadWritePrimitiveArray()464     public void testReadWritePrimitiveArray() {
465         // int32 (n)
466         checkKeyGetAndSet("android.sensor.info.sensitivityRange", int[].class,
467                 new int[] {
468                         0xC0FFEE, 0xDEADF00D
469                 });
470 
471         // byte (n)
472         checkKeyGetAndSet("android.statistics.faceScores", byte[].class, new byte[] {
473                 1, 2, 3, 4
474         });
475 
476         // int64 (n)
477         checkKeyGetAndSet("android.scaler.availableProcessedMinDurations", long[].class,
478                 new long[] {
479                         0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
480                 });
481 
482         // float (n)
483         checkKeyGetAndSet("android.lens.info.availableApertures", float[].class,
484                 new float[] {
485                         Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
486                 });
487 
488         // double (n) -- in particular double x 3
489         checkKeyGetAndSet("android.jpeg.gpsCoordinates", double[].class,
490                 new double[] {
491                         Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
492                 });
493 
494         // rational (n) -- in particular rational x 9
495         checkKeyGetAndSet("android.sensor.calibrationTransform1", Rational[].class,
496                 new Rational[] {
497                         new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
498                         new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
499                         new Rational(12, 13), new Rational(14, 15), new Rational(15, 16)
500                 });
501 
502         /**
503          * Weirder cases, that don't map 1:1 with the native types
504          */
505 
506         // bool (n) -- with TYPE_BYTE
507         checkKeyGetAndSet("android.control.aeLock", boolean[].class, new boolean[] {
508                 true, false, true
509         });
510 
511         // integer (n) -- with TYPE_BYTE
512         checkKeyGetAndSet("android.control.aeAvailableModes", int[].class, new int[] {
513             1, 2, 3, 4
514         });
515     }
516 
517     private enum ColorCorrectionMode {
518         TRANSFORM_MATRIX,
519         FAST,
520         HIGH_QUALITY
521     }
522 
523     private enum AeAntibandingMode {
524         OFF,
525         _50HZ,
526         _60HZ,
527         AUTO
528     }
529 
530     private enum AvailableFormat {
531         RAW_SENSOR,
532         YV12,
533         YCrCb_420_SP,
534         IMPLEMENTATION_DEFINED,
535         YCbCr_420_888,
536         BLOB
537     }
538 
539     @SmallTest
testReadWriteEnum()540     public void testReadWriteEnum() {
541         // byte (single)
542         checkKeyGetAndSet("android.colorCorrection.mode", ColorCorrectionMode.class,
543                 ColorCorrectionMode.HIGH_QUALITY);
544 
545         // byte (single)
546         checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
547                 AeAntibandingMode.AUTO);
548 
549         // byte (n)
550         checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
551                 AeAntibandingMode[].class, new AeAntibandingMode[] {
552                         AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
553                         AeAntibandingMode.AUTO
554                 });
555 
556         /**
557          * Stranger cases that don't use byte enums
558          */
559         // int (n)
560         checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
561                 new AvailableFormat[] {
562                         AvailableFormat.RAW_SENSOR,
563                         AvailableFormat.YV12,
564                         AvailableFormat.IMPLEMENTATION_DEFINED,
565                         AvailableFormat.YCbCr_420_888,
566                         AvailableFormat.BLOB
567                 });
568 
569     }
570 
571     @SmallTest
testReadWriteEnumWithCustomValues()572     public void testReadWriteEnumWithCustomValues() {
573         MarshalQueryableEnum.registerEnumValues(AeAntibandingMode.class, new int[] {
574             0,
575             10,
576             20,
577             30
578         });
579 
580         // byte (single)
581         checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
582                 AeAntibandingMode.AUTO);
583 
584         // byte (n)
585         checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
586                 AeAntibandingMode[].class, new AeAntibandingMode[] {
587                         AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
588                         AeAntibandingMode.AUTO
589                 });
590 
591         byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
592                 .getTag("android.control.aeAvailableAntibandingModes"));
593         byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
594         assertArrayEquals(expectedValues, aeAntibandingModeValues);
595 
596 
597         /**
598          * Stranger cases that don't use byte enums
599          */
600         // int (n)
601         MarshalQueryableEnum.registerEnumValues(AvailableFormat.class, new int[] {
602             0x20,
603             0x32315659,
604             0x11,
605             0x22,
606             0x23,
607             0x21,
608         });
609 
610         checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
611                 new AvailableFormat[] {
612                         AvailableFormat.RAW_SENSOR,
613                         AvailableFormat.YV12,
614                         AvailableFormat.IMPLEMENTATION_DEFINED,
615                         AvailableFormat.YCbCr_420_888,
616                         AvailableFormat.BLOB
617                 });
618 
619         Key<AvailableFormat[]> availableFormatsKey =
620                 new Key<AvailableFormat[]>("android.scaler.availableFormats",
621                         AvailableFormat[].class);
622         byte[] availableFormatValues = mMetadata.readValues(CameraMetadataNative
623                 .getTag(availableFormatsKey.getName()));
624 
625         int[] expectedIntValues = new int[] {
626                 0x20,
627                 0x32315659,
628                 0x22,
629                 0x23,
630                 0x21
631         };
632 
633         ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
634 
635         assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
636         for (int i = 0; i < expectedIntValues.length; ++i) {
637             assertEquals(expectedIntValues[i], bf.getInt());
638         }
639     }
640 
641     @SmallTest
testReadWriteSize()642     public void testReadWriteSize() {
643         // int32 x n
644         checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
645 
646         // int32 x 2 x n
647         checkKeyGetAndSet("android.scaler.availableJpegSizes", Size[].class, new Size[] {
648             new Size(123, 456),
649             new Size(0xDEAD, 0xF00D),
650             new Size(0xF00, 0xB00)
651         });
652     }
653 
654     @SmallTest
testReadWriteRggbChannelVector()655     public void testReadWriteRggbChannelVector() {
656         // int32 x n
657         checkKeyMarshal("android.colorCorrection.gains",
658                 new RggbChannelVector(1.0f, 2.1f, 3.2f, 4.5f),
659                 toByteArray(1.0f, 2.1f, 3.2f, 4.5f));
660 
661         // int32 x 2 x n [pretend; actual is not array]
662         checkKeyMarshal("android.colorCorrection.gains",
663                 new RggbChannelVector[] {
664                     new RggbChannelVector(1.0f, 2.0f, 3.0f, 4.0f),
665                     new RggbChannelVector(9.0f, 8.0f, 7.0f, 6.0f),
666                     new RggbChannelVector(1.3f, 5.5f, 2.4f, 6.7f),
667                 }, toByteArray(
668                         1.0f, 2.0f, 3.0f, 4.0f,
669                         9.0f, 8.0f, 7.0f, 6.0f,
670                         1.3f, 5.5f, 2.4f, 6.7f
671                 ));
672     }
673 
674     @SmallTest
testReadWriteSizeF()675     public void testReadWriteSizeF() {
676         // int32 x n
677         checkKeyMarshal("android.sensor.info.physicalSize",
678                 new SizeF(123f, 456f),
679                 toByteArray(123f, 456f));
680 
681         // int32 x 2 x n
682         checkKeyMarshal("android.sensor.info.physicalSize",
683                 new SizeF[] {
684                     new SizeF(123f, 456f),
685                     new SizeF(1.234f, 4.567f),
686                     new SizeF(999.0f, 555.0f)
687                 },
688                 toByteArray(
689                         123f, 456f,
690                         1.234f, 4.567f,
691                         999.0f, 555.0f)
692         );
693     }
694 
695     @SmallTest
testReadWriteRectangle()696     public void testReadWriteRectangle() {
697         // int32 x n
698         checkKeyMarshal("android.scaler.cropRegion",
699                 // x1, y1, x2, y2
700                 new Rect(10, 11, 1280, 1024),
701                 // x, y, width, height
702                 toByteArray(10, 11, 1280 - 10, 1024 - 11));
703 
704         // int32 x 2 x n  [actually not array, but we pretend it is]
705         checkKeyMarshal("android.scaler.cropRegion", new Rect[] {
706             new Rect(110, 111, 11280, 11024),
707             new Rect(210, 111, 21280, 21024),
708             new Rect(310, 111, 31280, 31024)
709         }, toByteArray(
710                 110, 111, 11280 - 110, 11024 - 111,
711                 210, 111, 21280 - 210, 21024 - 111,
712                 310, 111, 31280 - 310, 31024 - 111
713         ));
714     }
715 
716     @SmallTest
testReadWriteMeteringRectangle()717     public void testReadWriteMeteringRectangle() {
718         // int32 x 5 x area_count [but we pretend it's a single element]
719         checkKeyMarshal("android.control.aeRegions",
720                 new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5),
721                 /* xmin, ymin, xmax, ymax, weight */
722                 toByteArray(1, 2, 1 + 100, 2 + 200, 5));
723 
724         // int32 x 5 x area_count
725         checkKeyMarshal("android.control.afRegions",
726                 new MeteringRectangle[] {
727                     new MeteringRectangle(/*x*/5, /*y*/6, /*width*/123, /*height*/456, /*weight*/7),
728                     new MeteringRectangle(/*x*/7, /*y*/8, /*width*/456, /*height*/999, /*weight*/6),
729                     new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5)
730                 },
731                 toByteArray(
732                         5, 6, 5 + 123, 6 + 456, 7,
733                         7, 8, 7 + 456, 8 + 999, 6,
734                         1, 2, 1 + 100, 2 + 200, 5
735         ));
736     }
737 
738     @SmallTest
testReadWriteHighSpeedVideoConfiguration()739     public void testReadWriteHighSpeedVideoConfiguration() {
740         // int32 x 5 x 1
741         checkKeyMarshal("android.control.availableHighSpeedVideoConfigurations",
742                 new HighSpeedVideoConfiguration(
743                         /*width*/1000, /*height*/255, /*fpsMin*/30, /*fpsMax*/200,
744                         /*batchSizeMax*/8),
745                 /* width, height, fpsMin, fpsMax */
746                 toByteArray(1000, 255, 30, 200, 8));
747 
748         // int32 x 5 x 3
749         checkKeyMarshal("android.control.availableHighSpeedVideoConfigurations",
750                 new HighSpeedVideoConfiguration[] {
751                     new HighSpeedVideoConfiguration(
752                             /*width*/1280, /*height*/720, /*fpsMin*/60, /*fpsMax*/120,
753                             /*batchSizeMax*/8),
754                     new HighSpeedVideoConfiguration(
755                             /*width*/123, /*height*/456, /*fpsMin*/1, /*fpsMax*/200,
756                             /*batchSizeMax*/4),
757                     new HighSpeedVideoConfiguration(
758                             /*width*/4096, /*height*/2592, /*fpsMin*/30, /*fpsMax*/60,
759                             /*batchSizeMax*/2)
760                 },
761                 toByteArray(
762                         1280, 720, 60, 120, 8,
763                         123, 456, 1, 200, 4,
764                         4096, 2592, 30, 60, 2
765         ));
766     }
767 
768     @SmallTest
testReadWriteColorSpaceTransform()769     public void testReadWriteColorSpaceTransform() {
770         // rational x 3 x 3
771         checkKeyMarshal("android.colorCorrection.transform",
772                 new ColorSpaceTransform(new Rational[] {
773                         new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
774                         new Rational(7, 8), new Rational(8, 9), new Rational(10, 11),
775                         new Rational(1, 5), new Rational(2, 8), new Rational(3, 9),
776                 }),
777                 toByteArray(
778                         1, 2, 3, 4, 5, 6,
779                         7, 8, 8, 9, 10, 11,
780                         1, 5, 1, 4, 1, 3));
781     }
782 
783     @SmallTest
testReadWritePoint()784     public void testReadWritePoint() {
785         // int32 x 2 [actually 'x n' but pretend it's a single value for now]
786         checkKeyMarshal("android.statistics.hotPixelMap",
787                 new Point(1, 2),
788                 toByteArray(1, 2));
789 
790         // int32 x 2 x samples
791         checkKeyMarshal("android.statistics.hotPixelMap",
792                 new Point[] {
793                     new Point(1, 2),
794                     new Point(3, 4),
795                     new Point(5, 6),
796                     new Point(7, 8),
797                 },
798                 toByteArray(
799                         1, 2,
800                         3, 4,
801                         5, 6,
802                         7, 8)
803         );
804     }
805 
806     @SmallTest
testReadWritePointF()807     public void testReadWritePointF() {
808         // float x 2 [actually 'x samples' but pretend it's a single value for now]
809         checkKeyMarshal(
810                 "android.sensor.profileToneCurve",
811                 new PointF(1.0f, 2.0f),
812                 toByteArray(1.0f, 2.0f));
813 
814         // float x 2 x samples
815         checkKeyMarshal("android.sensor.profileToneCurve",
816                 new PointF[] {
817                     new PointF(1.0f, 2.0f),
818                     new PointF(3.0f, 4.0f),
819                     new PointF(5.0f, 6.0f),
820                     new PointF(7.0f, 8.0f),
821                 },
822                 toByteArray(
823                         1.0f, 2.0f,
824                         3.0f, 4.0f,
825                         5.0f, 6.0f,
826                         7.0f, 8.0f));
827     }
828 
829     @SmallTest
testReadWritePair()830     public void testReadWritePair() {
831         // float x 2
832         checkKeyMarshal("android.lens.focusRange",
833                 new TypeReference<Pair<Float, Float>>() {{ }},
834                 Pair.create(1.0f / 2.0f, 1.0f / 3.0f),
835                 toByteArray(1.0f / 2.0f, 1.0f / 3.0f));
836 
837         // byte, int (fake from TYPE_BYTE)
838         // This takes advantage of the TYPE_BYTE -> int marshaler designed for enums.
839         checkKeyMarshal("android.flash.mode",
840                 new TypeReference<Pair<Byte, Integer>>() {{ }},
841                 Pair.create((byte)123, 22),
842                 toByteArray((byte)123, (byte)22));
843     }
844 
845     @SmallTest
testReadWriteRange()846     public void testReadWriteRange() {
847         // int32 x 2
848         checkKeyMarshal("android.control.aeTargetFpsRange",
849                 new TypeReference<Range<Integer>>() {{ }},
850                 Range.create(123, 456),
851                 toByteArray(123, 456));
852 
853         // int64 x 2
854         checkKeyMarshal("android.sensor.info.exposureTimeRange",
855                 new TypeReference<Range<Long>>() {{ }},
856                 Range.create(123L, 456L),
857                 toByteArray(123L, 456L));
858     }
859 
860     @SmallTest
testReadWriteStreamConfiguration()861     public void testReadWriteStreamConfiguration() {
862         // int32 x 4 x n
863         checkKeyMarshal("android.scaler.availableStreamConfigurations",
864                 new StreamConfiguration[] {
865                     new StreamConfiguration(ImageFormat.YUV_420_888, 640, 480, /*input*/false),
866                     new StreamConfiguration(ImageFormat.RGB_565, 320, 240, /*input*/true),
867                 },
868                 toByteArray(
869                         ImageFormat.YUV_420_888, 640, 480, /*input*/0,
870                         ImageFormat.RGB_565, 320, 240, /*input*/1)
871         );
872     }
873 
874     @SmallTest
testReadWriteStreamConfigurationDuration()875     public void testReadWriteStreamConfigurationDuration() {
876         // Avoid sign extending ints when converting to a long
877         final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
878 
879         // int64 x 4 x n
880         checkKeyMarshal("android.scaler.availableMinFrameDurations",
881                 new StreamConfigurationDuration[] {
882                     new StreamConfigurationDuration(
883                             ImageFormat.YUV_420_888, 640, 480, /*duration*/123L),
884                     new StreamConfigurationDuration(
885                             ImageFormat.RGB_565, 320, 240, /*duration*/345L),
886                 },
887                 toByteArray(
888                         ImageFormat.YUV_420_888 & MASK_UNSIGNED_INT, 640L, 480L, /*duration*/123L,
889                         ImageFormat.RGB_565 & MASK_UNSIGNED_INT, 320L, 240L, /*duration*/345L)
890         );
891     }
892 
893 
894     @SmallTest
testReadWriteReprocessFormatsMap()895     public void testReadWriteReprocessFormatsMap() {
896 
897         // final int RAW_OPAQUE = 0x24; // TODO: add RAW_OPAQUE to ImageFormat
898         final int RAW16 = ImageFormat.RAW_SENSOR;
899         final int YUV_420_888 = ImageFormat.YUV_420_888;
900         final int BLOB = 0x21;
901 
902         // TODO: also test HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as an output
903         int[] contents = new int[] {
904                 YUV_420_888, 3, YUV_420_888, ImageFormat.NV21, BLOB,
905                 RAW16, 2, YUV_420_888, BLOB,
906 
907         };
908 
909         // int32 x n
910         Key<ReprocessFormatsMap> key = new Key<ReprocessFormatsMap>(
911                 "android.scaler.availableInputOutputFormatsMap", ReprocessFormatsMap.class);
912         mMetadata.writeValues(key.getTag(), toByteArray(contents));
913 
914         ReprocessFormatsMap map = mMetadata.get(key);
915 
916         /*
917          * Make sure the inputs/outputs were what we expected.
918          * - Use public image format constants here.
919          */
920 
921         int[] expectedInputs = new int[] {
922                 YUV_420_888, RAW16
923         };
924         assertArrayEquals(expectedInputs, map.getInputs());
925 
926         int[] expectedYuvOutputs = new int[] {
927                 YUV_420_888, ImageFormat.NV21, ImageFormat.JPEG,
928         };
929         assertArrayEquals(expectedYuvOutputs, map.getOutputs(ImageFormat.YUV_420_888));
930 
931         int[] expectedRaw16Outputs = new int[] {
932                 YUV_420_888, ImageFormat.JPEG,
933         };
934         assertArrayEquals(expectedRaw16Outputs, map.getOutputs(ImageFormat.RAW_SENSOR));
935 
936         // Finally, do a round-trip check for consistency
937         checkKeyMarshal(
938                 "android.scaler.availableInputOutputFormatsMap",
939                 new ReprocessFormatsMap(contents),
940                 toByteArray(contents)
941         );
942     }
943 
944     @SmallTest
testReadWriteString()945     public void testReadWriteString() {
946         // (byte) string
947         Key<String> gpsProcessingMethodKey =
948                 new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
949 
950         String helloWorld = new String("HelloWorld");
951         byte[] helloWorldBytes = new byte[] {
952                 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0' };
953 
954         mMetadata.set(gpsProcessingMethodKey, helloWorld);
955 
956         String actual = mMetadata.get(gpsProcessingMethodKey);
957         assertEquals(helloWorld, actual);
958 
959         byte[] actualBytes = mMetadata.readValues(getTag(gpsProcessingMethodKey.getName()));
960         assertArrayEquals(helloWorldBytes, actualBytes);
961 
962         // Does not yet test as a string[] since we don't support that in native code.
963 
964         // (byte) string
965         Key<String[]> gpsProcessingMethodKeyArray =
966                 new Key<String[]>("android.jpeg.gpsProcessingMethod", String[].class);
967 
968         String[] gpsStrings = new String[] { "HelloWorld", "FooBar", "Shazbot" };
969         byte[] gpsBytes = new byte[] {
970                 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0',
971                 'F', 'o', 'o', 'B', 'a', 'r', '\0',
972                 'S', 'h', 'a', 'z', 'b', 'o', 't', '\0'};
973 
974         mMetadata.set(gpsProcessingMethodKeyArray, gpsStrings);
975 
976         String[] actualArray = mMetadata.get(gpsProcessingMethodKeyArray);
977         assertArrayEquals(gpsStrings, actualArray);
978 
979         byte[] actualBytes2 = mMetadata.readValues(getTag(gpsProcessingMethodKeyArray.getName()));
980         assertArrayEquals(gpsBytes, actualBytes2);
981     }
982 
983     @SmallTest
testReadWriteOverride()984     public void testReadWriteOverride() {
985         //
986         // android.scaler.availableFormats (int x n array)
987         //
988         int[] availableFormats = new int[] {
989                 0x20,       // RAW_SENSOR
990                 0x32315659, // YV12
991                 0x11,       // YCrCb_420_SP
992                 0x100,      // ImageFormat.JPEG
993                 0x22,       // IMPLEMENTATION_DEFINED
994                 0x23,       // YCbCr_420_888
995         };
996         int[] expectedIntValues = new int[] {
997                 0x20,       // RAW_SENSOR
998                 0x32315659, // YV12
999                 0x11,       // YCrCb_420_SP
1000                 0x21,       // BLOB
1001                 0x22,       // IMPLEMENTATION_DEFINED
1002                 0x23,       // YCbCr_420_888
1003         };
1004         int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats");
1005 
1006         Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS.getNativeKey();
1007 
1008         validateArrayMetadataReadWriteOverride(formatKey, availableFormats,
1009                 expectedIntValues, availableFormatTag);
1010 
1011         //
1012         // android.statistics.faces (Face x n array)
1013         //
1014         int[] expectedFaceIds = new int[] {1, 2, 3, 4, 5};
1015         byte[] expectedFaceScores = new byte[] {10, 20, 30, 40, 50};
1016         int numFaces = expectedFaceIds.length;
1017         Rect[] expectedRects = new Rect[numFaces];
1018         for (int i = 0; i < numFaces; i++) {
1019             expectedRects[i] = new Rect(i*4 + 1, i * 4 + 2, i * 4 + 3, i * 4 + 4);
1020         }
1021         int[] expectedFaceLM = new int[] {
1022                 1, 2, 3, 4, 5, 6,
1023                 7, 8, 9, 10, 11, 12,
1024                 13, 14, 15, 16, 17, 18,
1025                 19, 20, 21, 22, 23, 24,
1026                 25, 26, 27, 28, 29, 30,
1027         };
1028         Point[] expectedFaceLMPoints = new Point[numFaces * 3];
1029         for (int i = 0; i < numFaces; i++) {
1030             expectedFaceLMPoints[i*3] = new Point(expectedFaceLM[i*6], expectedFaceLM[i*6+1]);
1031             expectedFaceLMPoints[i*3+1] = new Point(expectedFaceLM[i*6+2], expectedFaceLM[i*6+3]);
1032             expectedFaceLMPoints[i*3+2] = new Point(expectedFaceLM[i*6+4], expectedFaceLM[i*6+5]);
1033         }
1034 
1035         /**
1036          * Read - FACE_DETECT_MODE == FULL
1037          */
1038         mMetadata.set(CaptureResult.STATISTICS_FACE_DETECT_MODE,
1039                 CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL);
1040         mMetadata.set(CaptureResult.STATISTICS_FACE_IDS, expectedFaceIds);
1041         mMetadata.set(CaptureResult.STATISTICS_FACE_SCORES, expectedFaceScores);
1042         mMetadata.set(CaptureResult.STATISTICS_FACE_RECTANGLES, expectedRects);
1043         mMetadata.set(CaptureResult.STATISTICS_FACE_LANDMARKS, expectedFaceLM);
1044         Face[] resultFaces = mMetadata.get(CaptureResult.STATISTICS_FACES);
1045         assertEquals(numFaces, resultFaces.length);
1046         for (int i = 0; i < numFaces; i++) {
1047             assertEquals(expectedFaceIds[i], resultFaces[i].getId());
1048             assertEquals(expectedFaceScores[i], resultFaces[i].getScore());
1049             assertEquals(expectedRects[i], resultFaces[i].getBounds());
1050             assertEquals(expectedFaceLMPoints[i*3], resultFaces[i].getLeftEyePosition());
1051             assertEquals(expectedFaceLMPoints[i*3+1], resultFaces[i].getRightEyePosition());
1052             assertEquals(expectedFaceLMPoints[i*3+2], resultFaces[i].getMouthPosition());
1053         }
1054 
1055         /**
1056          * Read - FACE_DETECT_MODE == SIMPLE
1057          */
1058         mMetadata.set(CaptureResult.STATISTICS_FACE_DETECT_MODE,
1059                 CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE);
1060         mMetadata.set(CaptureResult.STATISTICS_FACE_SCORES, expectedFaceScores);
1061         mMetadata.set(CaptureResult.STATISTICS_FACE_RECTANGLES, expectedRects);
1062         Face[] resultSimpleFaces = mMetadata.get(CaptureResult.STATISTICS_FACES);
1063         assertEquals(numFaces, resultSimpleFaces.length);
1064         for (int i = 0; i < numFaces; i++) {
1065             assertEquals(Face.ID_UNSUPPORTED, resultSimpleFaces[i].getId());
1066             assertEquals(expectedFaceScores[i], resultSimpleFaces[i].getScore());
1067             assertEquals(expectedRects[i], resultSimpleFaces[i].getBounds());
1068             assertNull(resultSimpleFaces[i].getLeftEyePosition());
1069             assertNull(resultSimpleFaces[i].getRightEyePosition());
1070             assertNull(resultSimpleFaces[i].getMouthPosition());
1071         }
1072 
1073         /**
1074          * Read/Write TonemapCurve
1075          */
1076         float[] red = new float[] {0.0f, 0.0f, 1.0f, 1.0f};
1077         float[] green = new float[] {0.0f, 1.0f, 1.0f, 0.0f};
1078         float[] blue = new float[] {
1079                 0.0000f, 0.0000f, 0.0667f, 0.2920f, 0.1333f, 0.4002f, 0.2000f, 0.4812f,
1080                 0.2667f, 0.5484f, 0.3333f, 0.6069f, 0.4000f, 0.6594f, 0.4667f, 0.7072f,
1081                 0.5333f, 0.7515f, 0.6000f, 0.7928f, 0.6667f, 0.8317f, 0.7333f, 0.8685f,
1082                 0.8000f, 0.9035f, 0.8667f, 0.9370f, 0.9333f, 0.9691f, 1.0000f, 1.0000f};
1083         TonemapCurve tcIn = new TonemapCurve(red, green, blue);
1084         mMetadata.set(CaptureResult.TONEMAP_CURVE, tcIn);
1085         float[] redOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_RED);
1086         float[] greenOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_GREEN);
1087         float[] blueOut = mMetadata.get(CaptureResult.TONEMAP_CURVE_BLUE);
1088         assertArrayEquals(red, redOut);
1089         assertArrayEquals(green, greenOut);
1090         assertArrayEquals(blue, blueOut);
1091         TonemapCurve tcOut = mMetadata.get(CaptureResult.TONEMAP_CURVE);
1092         assertEquals(tcIn, tcOut);
1093         mMetadata.set(CaptureResult.TONEMAP_CURVE_GREEN, null);
1094         // If any of channel has null curve, return a null TonemapCurve
1095         assertNull(mMetadata.get(CaptureResult.TONEMAP_CURVE));
1096     }
1097 
1098     /**
1099      * Set the raw native value of the available stream configurations; ensure that
1100      * the read-out managed value is consistent with what we write in.
1101      */
1102     @SmallTest
testOverrideStreamConfigurationMap()1103     public void testOverrideStreamConfigurationMap() {
1104 
1105         /*
1106          * First, write all the raw values:
1107          * - availableStreamConfigurations
1108          * - availableMinFrameDurations
1109          * - availableStallDurations
1110          *
1111          * Then, read this out as a synthetic multi-key 'streamConfigurationMap'
1112          *
1113          * Finally, validate that the map was unmarshaled correctly
1114          * and is converting the internal formats to public formats properly.
1115          */
1116 
1117         //
1118         // android.scaler.availableStreamConfigurations (int x n x 4 array)
1119         //
1120         final int OUTPUT = 0;
1121         final int INPUT = 1;
1122         int[] rawAvailableStreamConfigs = new int[] {
1123                 0x20, 3280, 2464, OUTPUT, // RAW16
1124                 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
1125                 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
1126                 0x21, 3264, 2448, OUTPUT, // BLOB
1127                 0x21, 3200, 2400, OUTPUT, // BLOB
1128                 0x21, 2592, 1944, OUTPUT, // BLOB
1129                 0x21, 2048, 1536, OUTPUT, // BLOB
1130                 0x21, 1920, 1080, OUTPUT, // BLOB
1131                 0x22, 640, 480, OUTPUT,   // IMPLEMENTATION_DEFINED
1132                 0x20, 320, 240, INPUT,   // RAW16
1133         };
1134         Key<StreamConfiguration[]> configKey =
1135                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS.getNativeKey();
1136         mMetadata.writeValues(configKey.getTag(),
1137                 toByteArray(rawAvailableStreamConfigs));
1138 
1139         //
1140         // android.scaler.availableMinFrameDurations (int x n x 4 array)
1141         //
1142         long[] expectedAvailableMinDurations = new long[] {
1143                 0x20, 3280, 2464, 33333331, // RAW16
1144                 0x23, 3264, 2448, 33333332, // YCbCr_420_888
1145                 0x23, 3200, 2400, 33333333, // YCbCr_420_888
1146                 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG
1147                 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG
1148                 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
1149                 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG
1150                 0x100, 1920, 1080, 33333338  // ImageFormat.JPEG
1151         };
1152         long[] rawAvailableMinDurations = new long[] {
1153                 0x20, 3280, 2464, 33333331, // RAW16
1154                 0x23, 3264, 2448, 33333332, // YCbCr_420_888
1155                 0x23, 3200, 2400, 33333333, // YCbCr_420_888
1156                 0x21, 3264, 2448, 33333334, // BLOB
1157                 0x21, 3200, 2400, 33333335, // BLOB
1158                 0x21, 2592, 1944, 33333336, // BLOB
1159                 0x21, 2048, 1536, 33333337, // BLOB
1160                 0x21, 1920, 1080, 33333338  // BLOB
1161         };
1162         Key<StreamConfigurationDuration[]> durationKey =
1163                 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS.getNativeKey();
1164         mMetadata.writeValues(durationKey.getTag(),
1165                 toByteArray(rawAvailableMinDurations));
1166 
1167         //
1168         // android.scaler.availableStallDurations (int x n x 4 array)
1169         //
1170         long[] expectedAvailableStallDurations = new long[] {
1171                 0x20, 3280, 2464, 0,        // RAW16
1172                 0x23, 3264, 2448, 0,        // YCbCr_420_888
1173                 0x23, 3200, 2400, 0,        // YCbCr_420_888
1174                 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG
1175                 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG
1176                 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
1177                 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG
1178                 0x100, 1920, 1080, 33333338  // ImageFormat.JPEG
1179         };
1180         // Note: RAW16 and YUV_420_888 omitted intentionally; omitted values should default to 0
1181         long[] rawAvailableStallDurations = new long[] {
1182                 0x21, 3264, 2448, 33333334, // BLOB
1183                 0x21, 3200, 2400, 33333335, // BLOB
1184                 0x21, 2592, 1944, 33333336, // BLOB
1185                 0x21, 2048, 1536, 33333337, // BLOB
1186                 0x21, 1920, 1080, 33333338  // BLOB
1187         };
1188         Key<StreamConfigurationDuration[]> stallDurationKey =
1189                 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS.getNativeKey();
1190         mMetadata.writeValues(stallDurationKey.getTag(),
1191                 toByteArray(rawAvailableStallDurations));
1192 
1193         //
1194         // android.scaler.streamConfigurationMap (synthetic as StreamConfigurationMap)
1195         //
1196         StreamConfigurationMap streamConfigMap = mMetadata.get(
1197                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1198 
1199         // Inputs
1200         checkStreamConfigurationMapByFormatSize(
1201                 streamConfigMap, ImageFormat.RAW_SENSOR, 320, 240, /*output*/false);
1202 
1203         // Outputs
1204         checkStreamConfigurationMapByFormatSize(
1205                 streamConfigMap, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, /*output*/true);
1206         checkStreamConfigurationMapByFormatSize(
1207                 streamConfigMap, ImageFormat.JPEG, 1920, 1080, /*output*/true);
1208         checkStreamConfigurationMapByFormatSize(
1209                 streamConfigMap, ImageFormat.JPEG, 2048, 1536, /*output*/true);
1210         checkStreamConfigurationMapByFormatSize(
1211                 streamConfigMap, ImageFormat.JPEG, 2592, 1944, /*output*/true);
1212         checkStreamConfigurationMapByFormatSize(
1213                 streamConfigMap, ImageFormat.JPEG, 3200, 2400, /*output*/true);
1214         checkStreamConfigurationMapByFormatSize(
1215                 streamConfigMap, ImageFormat.YUV_420_888, 3200, 2400, /*output*/true);
1216         checkStreamConfigurationMapByFormatSize(
1217                 streamConfigMap, ImageFormat.YUV_420_888, 3264, 2448, /*output*/true);
1218         checkStreamConfigurationMapByFormatSize(
1219                 streamConfigMap, ImageFormat.RAW_SENSOR, 3280, 2464, /*output*/true);
1220 
1221         // Min Frame Durations
1222 
1223         final int DURATION_TUPLE_SIZE = 4;
1224         for (int i = 0; i < expectedAvailableMinDurations.length; i += DURATION_TUPLE_SIZE) {
1225             checkStreamConfigurationMapDurationByFormatSize(
1226                     streamConfigMap,
1227                     (int)expectedAvailableMinDurations[i],
1228                     (int)expectedAvailableMinDurations[i+1],
1229                     (int)expectedAvailableMinDurations[i+2],
1230                     Duration.MinFrame,
1231                     expectedAvailableMinDurations[i+3]);
1232         }
1233 
1234         // Stall Frame Durations
1235 
1236         for (int i = 0; i < expectedAvailableStallDurations.length; i += DURATION_TUPLE_SIZE) {
1237             checkStreamConfigurationMapDurationByFormatSize(
1238                     streamConfigMap,
1239                     (int)expectedAvailableStallDurations[i],
1240                     (int)expectedAvailableStallDurations[i+1],
1241                     (int)expectedAvailableStallDurations[i+2],
1242                     Duration.Stall,
1243                     expectedAvailableStallDurations[i+3]);
1244         }
1245     }
1246 
assertKeyValueEquals(T expected, CameraCharacteristics.Key<T> key)1247     private <T> void assertKeyValueEquals(T expected, CameraCharacteristics.Key<T> key) {
1248         assertKeyValueEquals(expected, key.getNativeKey());
1249     }
1250 
assertKeyValueEquals(T expected, Key<T> key)1251     private <T> void assertKeyValueEquals(T expected, Key<T> key) {
1252         T actual = mMetadata.get(key);
1253 
1254         assertEquals("Expected value for key " + key + " to match", expected, actual);
1255     }
1256 
1257     @SmallTest
testOverrideMaxRegions()1258     public void testOverrideMaxRegions() {
1259         // All keys are null before doing any writes.
1260         assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
1261         assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
1262         assertKeyValueEquals(null, CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
1263 
1264         mMetadata.set(CameraCharacteristics.CONTROL_MAX_REGIONS,
1265                 new int[] { /*AE*/1, /*AWB*/2, /*AF*/3 });
1266 
1267         // All keys are the expected value after doing a write
1268         assertKeyValueEquals(1, CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
1269         assertKeyValueEquals(2, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
1270         assertKeyValueEquals(3, CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
1271     }
1272 
1273     @SmallTest
testOverrideMaxNumOutputStreams()1274     public void testOverrideMaxNumOutputStreams() {
1275         // All keys are null before doing any writes.
1276         assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
1277         assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
1278         assertKeyValueEquals(null, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
1279 
1280         mMetadata.set(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS,
1281                 new int[] { /*AE*/1, /*AWB*/2, /*AF*/3 });
1282 
1283         // All keys are the expected value after doing a write
1284         assertKeyValueEquals(1, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
1285         assertKeyValueEquals(2, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
1286         assertKeyValueEquals(3, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
1287     }
1288 
1289     @SmallTest
testCaptureResult()1290     public void testCaptureResult() {
1291         mMetadata.set(CaptureRequest.CONTROL_AE_MODE,
1292                 CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH);
1293 
1294         if (VERBOSE) mMetadata.dumpToLog();
1295 
1296         CaptureResult captureResult = new CaptureResult(mMetadata, /*sequenceId*/0);
1297 
1298         List<CaptureResult.Key<?>> allKeys = captureResult.getKeys();
1299         if (VERBOSE) Log.v(TAG, "testCaptureResult: key list size " + allKeys);
1300         for (CaptureResult.Key<?> key : captureResult.getKeys()) {
1301             if (VERBOSE) {
1302                 Log.v(TAG,
1303                     "testCaptureResult: key " + key + " value" + captureResult.get(key));
1304             }
1305         }
1306 
1307         assertTrue(allKeys.size() >= 1); // FIXME: android.statistics.faces counts as a key
1308         assertTrue(allKeys.contains(CaptureResult.CONTROL_AE_MODE));
1309 
1310         assertEquals(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH,
1311                 (int)captureResult.get(CaptureResult.CONTROL_AE_MODE));
1312     }
1313 
checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap, int format, int width, int height, boolean output)1314     private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap,
1315             int format, int width, int height,
1316             boolean output) {
1317 
1318         /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */
1319         final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class;
1320 
1321         android.util.Size[] sizes;
1322         int[] formats;
1323 
1324         if (output) {
1325             if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
1326                 sizes = configMap.getOutputSizes(IMPLEMENTATION_DEFINED_OUTPUT_CLASS);
1327                 // in this case the 'is output format supported' is vacuously true
1328                 formats = new int[] { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED };
1329             } else {
1330                 sizes = configMap.getOutputSizes(format);
1331                 formats = configMap.getOutputFormats();
1332                 assertTrue("Format must be supported by stream configuration map",
1333                         configMap.isOutputSupportedFor(format));
1334             }
1335         } else {
1336             // NOTE: No function to do input sizes from IMPL_DEFINED, so it would just fail for that
1337             sizes = configMap.getInputSizes(format);
1338             formats = configMap.getInputFormats();
1339         }
1340 
1341         android.util.Size expectedSize = new android.util.Size(width, height);
1342 
1343         assertArrayContains(format, formats);
1344         assertArrayContains(expectedSize, sizes);
1345     }
1346 
1347     private enum Duration {
1348         MinFrame,
1349         Stall
1350     }
1351 
checkStreamConfigurationMapDurationByFormatSize( StreamConfigurationMap configMap, int format, int width, int height, Duration durationKind, long expectedDuration)1352     private static void checkStreamConfigurationMapDurationByFormatSize(
1353             StreamConfigurationMap configMap,
1354             int format, int width, int height, Duration durationKind, long expectedDuration) {
1355 
1356         /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */
1357         final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class;
1358 
1359         long actualDuration;
1360 
1361         android.util.Size size = new android.util.Size(width, height);
1362         switch (durationKind) {
1363             case MinFrame:
1364                 if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
1365                     actualDuration = configMap.getOutputMinFrameDuration(
1366                             IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size);
1367                 } else {
1368                     actualDuration = configMap.getOutputMinFrameDuration(format, size);
1369                 }
1370 
1371                 break;
1372             case Stall:
1373                 if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
1374                     actualDuration = configMap.getOutputStallDuration(
1375                             IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size);
1376                 } else {
1377                     actualDuration = configMap.getOutputStallDuration(format, size);
1378                 }
1379 
1380                 break;
1381             default:
1382                 throw new AssertionError();
1383         }
1384 
1385         assertEquals("Expected " + durationKind + " to match actual value", expectedDuration,
1386                 actualDuration);
1387     }
1388 
1389     /**
1390      * Validate metadata array tag read/write override.
1391      *
1392      * <p>Only support long and int array for now, can be easily extend to support other
1393      * primitive arrays.</p>
1394      */
validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues, T expectedReadValues, int tag)1395     private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues,
1396             T expectedReadValues, int tag) {
1397         Class<?> type = expectedWriteValues.getClass();
1398         if (!type.isArray()) {
1399             throw new IllegalArgumentException("This function expects an key with array type");
1400         } else if (type != int[].class && type != long[].class) {
1401             throw new IllegalArgumentException("This function expects long or int array values");
1402         }
1403 
1404         // Write
1405         mMetadata.set(key, expectedWriteValues);
1406 
1407         byte[] readOutValues = mMetadata.readValues(tag);
1408 
1409         ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder());
1410 
1411         int readValuesLength = Array.getLength(expectedReadValues);
1412         int readValuesNumBytes = readValuesLength * 4;
1413         if (type == long[].class) {
1414             readValuesNumBytes = readValuesLength * 8;
1415         }
1416 
1417         assertEquals(readValuesNumBytes, readOutValues.length);
1418         for (int i = 0; i < readValuesLength; ++i) {
1419             if (type == int[].class) {
1420                 assertEquals(Array.getInt(expectedReadValues, i), bf.getInt());
1421             } else if (type == long[].class) {
1422                 assertEquals(Array.getLong(expectedReadValues, i), bf.getLong());
1423             }
1424         }
1425 
1426         // Read
1427         byte[] readOutValuesAsByteArray = new byte[readValuesNumBytes];
1428         ByteBuffer readOutValuesByteBuffer =
1429                 ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder());
1430         for (int i = 0; i < readValuesLength; ++i) {
1431             if (type == int[].class) {
1432                 readOutValuesByteBuffer.putInt(Array.getInt(expectedReadValues, i));
1433             } else if (type == long[].class) {
1434                 readOutValuesByteBuffer.putLong(Array.getLong(expectedReadValues, i));
1435             }
1436         }
1437         mMetadata.writeValues(tag, readOutValuesAsByteArray);
1438 
1439         T result = mMetadata.get(key);
1440         assertNotNull(key.getName() + " result shouldn't be null", result);
1441         assertArrayEquals(expectedWriteValues, result);
1442     }
1443 
1444     // TODO: move somewhere else
1445     @SmallTest
testToByteArray()1446     public void testToByteArray() {
1447         assertArrayEquals(new byte[] { 5, 0, 0, 0, 6, 0, 0, 0 },
1448                 toByteArray(5, 6));
1449         assertArrayEquals(new byte[] { 5, 0, 6, 0, },
1450                 toByteArray((short)5, (short)6));
1451         assertArrayEquals(new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
1452                                         (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,},
1453                 toByteArray(~0, ~0));
1454 
1455         assertArrayEquals(new byte[] { (byte)0xAB, (byte)0xFF, 0, 0,
1456                 0x0D, (byte)0xF0, (byte)0xAD, (byte)0xDE },
1457                 toByteArray(0xFFAB, 0xDEADF00D));
1458     }
1459 }
1460