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