Home | History | Annotate | Download | only in unit
      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
     92     public void setUp() {
     93         mMetadata = new CameraMetadataNative();
     94     }
     95 
     96     @Override
     97     public void tearDown() throws Exception {
     98         mMetadata = null;
     99     }
    100 
    101     @SmallTest
    102     public void testNew() {
    103         assertEquals(0, mMetadata.getEntryCount());
    104         assertTrue(mMetadata.isEmpty());
    105     }
    106 
    107     @SmallTest
    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
    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
    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      */
    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 
    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 
    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 
    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 
    356     private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected) {
    357         checkKeyGetAndSet(keyStr, typeToken, expected, /*reuse*/false);
    358     }
    359 
    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      */
    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      */
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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 
   1237     private <T> void assertKeyValueEquals(T expected, CameraCharacteristics.Key<T> key) {
   1238         assertKeyValueEquals(expected, key.getNativeKey());
   1239     }
   1240 
   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
   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
   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
   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 
   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 
   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      */
   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
   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