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
17package com.android.mediaframeworktest.unit;
18
19import android.os.Parcel;
20import android.test.suitebuilder.annotation.SmallTest;
21import android.graphics.Point;
22import android.graphics.Rect;
23import android.hardware.camera2.CameraCharacteristics;
24import android.hardware.camera2.CaptureResult;
25import android.hardware.camera2.Face;
26import android.hardware.camera2.Rational;
27import android.hardware.camera2.Size;
28import android.hardware.camera2.impl.CameraMetadataNative;
29
30import static android.hardware.camera2.impl.CameraMetadataNative.*;
31
32import java.lang.reflect.Array;
33import java.nio.ByteBuffer;
34import java.nio.ByteOrder;
35
36/**
37 * <pre>
38 * adb shell am instrument \
39 *      -e class 'com.android.mediaframeworktest.unit.CameraMetadataTest' \
40 *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
41 * </pre>
42 */
43public class CameraMetadataTest extends junit.framework.TestCase {
44
45    CameraMetadataNative mMetadata;
46    Parcel mParcel;
47
48    // Sections
49    static final int ANDROID_COLOR_CORRECTION = 0;
50    static final int ANDROID_CONTROL = 1;
51
52    // Section starts
53    static final int ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16;
54    static final int ANDROID_CONTROL_START = ANDROID_CONTROL << 16;
55
56    // Tags
57    static final int ANDROID_COLOR_CORRECTION_MODE = ANDROID_COLOR_CORRECTION_START;
58    static final int ANDROID_COLOR_CORRECTION_TRANSFORM = ANDROID_COLOR_CORRECTION_START + 1;
59    static final int ANDROID_COLOR_CORRECTION_GAINS = ANDROID_COLOR_CORRECTION_START + 2;
60
61    static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START;
62    static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1;
63
64    @Override
65    public void setUp() {
66        mMetadata = new CameraMetadataNative();
67        mParcel = Parcel.obtain();
68    }
69
70    @Override
71    public void tearDown() throws Exception {
72        mMetadata = null;
73
74        mParcel.recycle();
75        mParcel = null;
76    }
77
78    @SmallTest
79    public void testNew() {
80        assertEquals(0, mMetadata.getEntryCount());
81        assertTrue(mMetadata.isEmpty());
82    }
83
84    @SmallTest
85    public void testGetTagFromKey() {
86
87        // Test success
88
89        assertEquals(ANDROID_COLOR_CORRECTION_MODE,
90                CameraMetadataNative.getTag("android.colorCorrection.mode"));
91        assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM,
92                CameraMetadataNative.getTag("android.colorCorrection.transform"));
93        assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
94                CameraMetadataNative.getTag("android.control.aeAntibandingMode"));
95        assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
96                CameraMetadataNative.getTag("android.control.aeExposureCompensation"));
97
98        // Test failures
99
100        try {
101            CameraMetadataNative.getTag(null);
102            fail("A null key should throw NPE");
103        } catch(NullPointerException e) {
104        }
105
106        try {
107            CameraMetadataNative.getTag("android.control");
108            fail("A section name only should not be a valid key");
109        } catch(IllegalArgumentException e) {
110        }
111
112        try {
113            CameraMetadataNative.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
114            fail("A valid section with an invalid tag name should not be a valid key");
115        } catch(IllegalArgumentException e) {
116        }
117
118        try {
119            CameraMetadataNative.getTag("android");
120            fail("A namespace name only should not be a valid key");
121        } catch(IllegalArgumentException e) {
122        }
123
124        try {
125            CameraMetadataNative.getTag("this.key.is.definitely.invalid");
126            fail("A completely fake key name should not be valid");
127        } catch(IllegalArgumentException e) {
128        }
129    }
130
131    @SmallTest
132    public void testGetTypeFromTag() {
133        assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
134        assertEquals(TYPE_RATIONAL, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
135        assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
136        assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
137        assertEquals(TYPE_INT32,
138                CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
139
140        try {
141            CameraMetadataNative.getNativeType(0xDEADF00D);
142            fail("No type should exist for invalid tag 0xDEADF00D");
143        } catch(IllegalArgumentException e) {
144        }
145    }
146
147    @SmallTest
148    public void testReadWriteValues() {
149        final byte ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
150        byte[] valueResult;
151
152        assertEquals(0, mMetadata.getEntryCount());
153        assertEquals(true, mMetadata.isEmpty());
154
155        //
156        // android.colorCorrection.mode (single enum byte)
157        //
158
159        assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
160
161        // Write/read null values
162        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, null);
163        assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
164
165        // Write 0 values
166        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {});
167
168        // Read 0 values
169        valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
170        assertNotNull(valueResult);
171        assertEquals(0, valueResult.length);
172
173        assertEquals(1, mMetadata.getEntryCount());
174        assertEquals(false, mMetadata.isEmpty());
175
176        // Write 1 value
177        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {
178            ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY
179        });
180
181        // Read 1 value
182        valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
183        assertNotNull(valueResult);
184        assertEquals(1, valueResult.length);
185        assertEquals(ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY, valueResult[0]);
186
187        assertEquals(1, mMetadata.getEntryCount());
188        assertEquals(false, mMetadata.isEmpty());
189
190        //
191        // android.colorCorrection.colorCorrectionGains (float x 4 array)
192        //
193
194        final float[] colorCorrectionGains = new float[] { 1.0f, 2.0f, 3.0f, 4.0f};
195        byte[] colorCorrectionGainsAsByteArray = new byte[colorCorrectionGains.length * 4];
196        ByteBuffer colorCorrectionGainsByteBuffer =
197                ByteBuffer.wrap(colorCorrectionGainsAsByteArray).order(ByteOrder.nativeOrder());
198        for (float f : colorCorrectionGains)
199            colorCorrectionGainsByteBuffer.putFloat(f);
200
201        // Read
202        assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS));
203        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_GAINS, colorCorrectionGainsAsByteArray);
204
205        // Write
206        assertArrayEquals(colorCorrectionGainsAsByteArray,
207                mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS));
208
209        assertEquals(2, mMetadata.getEntryCount());
210        assertEquals(false, mMetadata.isEmpty());
211
212        // Erase
213        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_GAINS, null);
214        assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_GAINS));
215        assertEquals(1, mMetadata.getEntryCount());
216    }
217
218    private static <T> void assertArrayEquals(T expected, T actual) {
219        assertEquals(Array.getLength(expected), Array.getLength(actual));
220
221        int len = Array.getLength(expected);
222        for (int i = 0; i < len; ++i) {
223            assertEquals(Array.get(expected, i), Array.get(actual, i));
224        }
225    }
226
227    private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
228        assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray());
229
230        Key<T> key = new Key<T>(keyStr, type);
231        assertNull(mMetadata.get(key));
232        mMetadata.set(key, null);
233        assertNull(mMetadata.get(key));
234        mMetadata.set(key, value);
235
236        T actual = mMetadata.get(key);
237        assertEquals(value, actual);
238    }
239
240    private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
241        assertTrue(type.isArray());
242
243        Key<T> key = new Key<T>(keyStr, type);
244        assertNull(mMetadata.get(key));
245        mMetadata.set(key, value);
246        assertArrayEquals(value, mMetadata.get(key));
247    }
248
249    @SmallTest
250    public void testReadWritePrimitive() {
251        // int32 (single)
252        checkKeyGetAndSet("android.control.aeExposureCompensation", Integer.TYPE, 0xC0FFEE);
253
254        // byte (single)
255        checkKeyGetAndSet("android.flash.maxEnergy", Byte.TYPE, (byte)6);
256
257        // int64 (single)
258        checkKeyGetAndSet("android.flash.firingTime", Long.TYPE, 0xABCD12345678FFFFL);
259
260        // float (single)
261        checkKeyGetAndSet("android.lens.aperture", Float.TYPE, Float.MAX_VALUE);
262
263        // double (single) -- technically double x 3, but we fake it
264        checkKeyGetAndSet("android.jpeg.gpsCoordinates", Double.TYPE, Double.MAX_VALUE);
265
266        // rational (single)
267        checkKeyGetAndSet("android.sensor.baseGainFactor", Rational.class, new Rational(1, 2));
268
269        /**
270         * Weirder cases, that don't map 1:1 with the native types
271         */
272
273        // bool (single) -- with TYPE_BYTE
274        checkKeyGetAndSet("android.control.aeLock", Boolean.TYPE, true);
275
276        // integer (single) -- with TYPE_BYTE
277        checkKeyGetAndSet("android.control.aePrecaptureTrigger", Integer.TYPE, 6);
278    }
279
280    @SmallTest
281    public void testReadWritePrimitiveArray() {
282        // int32 (n)
283        checkKeyGetAndSetArray("android.sensor.info.sensitivityRange", int[].class,
284                new int[] {
285                        0xC0FFEE, 0xDEADF00D
286                });
287
288        // byte (n)
289        checkKeyGetAndSetArray("android.statistics.faceScores", byte[].class, new byte[] {
290                1, 2, 3, 4
291        });
292
293        // int64 (n)
294        checkKeyGetAndSetArray("android.scaler.availableProcessedMinDurations", long[].class,
295                new long[] {
296                        0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
297                });
298
299        // float (n)
300        checkKeyGetAndSetArray("android.lens.info.availableApertures", float[].class,
301                new float[] {
302                        Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
303                });
304
305        // double (n) -- in particular double x 3
306        checkKeyGetAndSetArray("android.jpeg.gpsCoordinates", double[].class,
307                new double[] {
308                        Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
309                });
310
311        // rational (n) -- in particular rational x 9
312        checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
313                new Rational[] {
314                        new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
315                        new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
316                        new Rational(12, 13), new Rational(14, 15), new Rational(15, 16)
317                });
318
319        /**
320         * Weirder cases, that don't map 1:1 with the native types
321         */
322
323        // bool (n) -- with TYPE_BYTE
324        checkKeyGetAndSetArray("android.control.aeLock", boolean[].class, new boolean[] {
325                true, false, true
326        });
327
328
329        // integer (n) -- with TYPE_BYTE
330        checkKeyGetAndSetArray("android.control.aeAvailableModes", int[].class, new int[] {
331            1, 2, 3, 4
332        });
333    }
334
335    private enum ColorCorrectionMode {
336        TRANSFORM_MATRIX,
337        FAST,
338        HIGH_QUALITY
339    }
340
341    private enum AeAntibandingMode {
342        OFF,
343        _50HZ,
344        _60HZ,
345        AUTO
346    }
347
348    // TODO: special values for the enum.
349    private enum AvailableFormat {
350        RAW_SENSOR,
351        YV12,
352        YCrCb_420_SP,
353        IMPLEMENTATION_DEFINED,
354        YCbCr_420_888,
355        BLOB
356    }
357
358    @SmallTest
359    public void testReadWriteEnum() {
360        // byte (single)
361        checkKeyGetAndSet("android.colorCorrection.mode", ColorCorrectionMode.class,
362                ColorCorrectionMode.HIGH_QUALITY);
363
364        // byte (single)
365        checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
366                AeAntibandingMode.AUTO);
367
368        // byte (n)
369        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
370                AeAntibandingMode[].class, new AeAntibandingMode[] {
371                        AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
372                        AeAntibandingMode.AUTO
373                });
374
375        /**
376         * Stranger cases that don't use byte enums
377         */
378        // int (n)
379        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
380                new AvailableFormat[] {
381                        AvailableFormat.RAW_SENSOR,
382                        AvailableFormat.YV12,
383                        AvailableFormat.IMPLEMENTATION_DEFINED,
384                        AvailableFormat.YCbCr_420_888,
385                        AvailableFormat.BLOB
386                });
387
388    }
389
390    @SmallTest
391    public void testReadWriteEnumWithCustomValues() {
392        CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
393            0,
394            10,
395            20,
396            30
397        });
398
399        // byte (single)
400        checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
401                AeAntibandingMode.AUTO);
402
403        // byte (n)
404        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
405                AeAntibandingMode[].class, new AeAntibandingMode[] {
406                        AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
407                        AeAntibandingMode.AUTO
408                });
409
410        Key<AeAntibandingMode[]> aeAntibandingModeKey =
411                new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
412                        AeAntibandingMode[].class);
413        byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
414                .getTag("android.control.aeAvailableAntibandingModes"));
415        byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
416        assertArrayEquals(expectedValues, aeAntibandingModeValues);
417
418
419        /**
420         * Stranger cases that don't use byte enums
421         */
422        // int (n)
423        CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
424            0x20,
425            0x32315659,
426            0x11,
427            0x22,
428            0x23,
429            0x21,
430        });
431
432        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
433                new AvailableFormat[] {
434                        AvailableFormat.RAW_SENSOR,
435                        AvailableFormat.YV12,
436                        AvailableFormat.IMPLEMENTATION_DEFINED,
437                        AvailableFormat.YCbCr_420_888,
438                        AvailableFormat.BLOB
439                });
440
441        Key<AvailableFormat[]> availableFormatsKey =
442                new Key<AvailableFormat[]>("android.scaler.availableFormats",
443                        AvailableFormat[].class);
444        byte[] availableFormatValues = mMetadata.readValues(CameraMetadataNative
445                .getTag(availableFormatsKey.getName()));
446
447        int[] expectedIntValues = new int[] {
448                0x20,
449                0x32315659,
450                0x22,
451                0x23,
452                0x21
453        };
454
455        ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
456
457        assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
458        for (int i = 0; i < expectedIntValues.length; ++i) {
459            assertEquals(expectedIntValues[i], bf.getInt());
460        }
461    }
462
463    @SmallTest
464    public void testReadWriteSize() {
465        // int32 x n
466        checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
467
468        // int32 x 2 x n
469        checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] {
470            new Size(123, 456),
471            new Size(0xDEAD, 0xF00D),
472            new Size(0xF00, 0xB00)
473        });
474    }
475
476    @SmallTest
477    public void testReadWriteRectangle() {
478        // int32 x n
479        checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024));
480
481        // int32 x 2 x n
482        checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] {
483            new Rect(110, 111, 11280, 11024),
484            new Rect(210, 111, 21280, 21024),
485            new Rect(310, 111, 31280, 31024)
486        });
487    }
488
489    @SmallTest
490    public void testReadWriteString() {
491        // (byte) string
492        Key<String> gpsProcessingMethodKey =
493                new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
494
495        String helloWorld = new String("HelloWorld");
496        byte[] helloWorldBytes = new byte[] {
497                'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0' };
498
499        mMetadata.set(gpsProcessingMethodKey, helloWorld);
500
501        String actual = mMetadata.get(gpsProcessingMethodKey);
502        assertEquals(helloWorld, actual);
503
504        byte[] actualBytes = mMetadata.readValues(getTag(gpsProcessingMethodKey.getName()));
505        assertArrayEquals(helloWorldBytes, actualBytes);
506
507        // Does not yet test as a string[] since we don't support that in native code.
508
509        // (byte) string
510        Key<String[]> gpsProcessingMethodKeyArray =
511                new Key<String[]>("android.jpeg.gpsProcessingMethod", String[].class);
512
513        String[] gpsStrings = new String[] { "HelloWorld", "FooBar", "Shazbot" };
514        byte[] gpsBytes = new byte[] {
515                'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0',
516                'F', 'o', 'o', 'B', 'a', 'r', '\0',
517                'S', 'h', 'a', 'z', 'b', 'o', 't', '\0'};
518
519        mMetadata.set(gpsProcessingMethodKeyArray, gpsStrings);
520
521        String[] actualArray = mMetadata.get(gpsProcessingMethodKeyArray);
522        assertArrayEquals(gpsStrings, actualArray);
523
524        byte[] actualBytes2 = mMetadata.readValues(getTag(gpsProcessingMethodKeyArray.getName()));
525        assertArrayEquals(gpsBytes, actualBytes2);
526    }
527
528    <T> void compareGeneric(T expected, T actual) {
529        assertEquals(expected, actual);
530    }
531
532    @SmallTest
533    public void testReadWriteOverride() {
534        //
535        // android.scaler.availableFormats (int x n array)
536        //
537        int[] availableFormats = new int[] {
538                0x20,       // RAW_SENSOR
539                0x32315659, // YV12
540                0x11,       // YCrCb_420_SP
541                0x100,      // ImageFormat.JPEG
542                0x22,       // IMPLEMENTATION_DEFINED
543                0x23,       // YCbCr_420_888
544        };
545        int[] expectedIntValues = new int[] {
546                0x20,       // RAW_SENSOR
547                0x32315659, // YV12
548                0x11,       // YCrCb_420_SP
549                0x21,       // BLOB
550                0x22,       // IMPLEMENTATION_DEFINED
551                0x23,       // YCbCr_420_888
552        };
553        int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats");
554
555        // Write
556        mMetadata.set(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, availableFormats);
557
558        byte[] availableFormatValues = mMetadata.readValues(availableFormatTag);
559
560        ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
561
562        assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
563        for (int i = 0; i < expectedIntValues.length; ++i) {
564            assertEquals(expectedIntValues[i], bf.getInt());
565        }
566        // Read
567        byte[] availableFormatsAsByteArray = new byte[expectedIntValues.length * 4];
568        ByteBuffer availableFormatsByteBuffer =
569                ByteBuffer.wrap(availableFormatsAsByteArray).order(ByteOrder.nativeOrder());
570        for (int value : expectedIntValues) {
571            availableFormatsByteBuffer.putInt(value);
572        }
573        mMetadata.writeValues(availableFormatTag, availableFormatsAsByteArray);
574
575        int[] resultFormats = mMetadata.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
576        assertNotNull("result available formats shouldn't be null", resultFormats);
577        assertArrayEquals(availableFormats, resultFormats);
578
579        //
580        // android.statistics.faces (Face x n array)
581        //
582        int[] expectedFaceIds = new int[] {1, 2, 3, 4, 5};
583        byte[] expectedFaceScores = new byte[] {10, 20, 30, 40, 50};
584        int numFaces = expectedFaceIds.length;
585        Rect[] expectedRects = new Rect[numFaces];
586        for (int i = 0; i < numFaces; i++) {
587            expectedRects[i] = new Rect(i*4 + 1, i * 4 + 2, i * 4 + 3, i * 4 + 4);
588        }
589        int[] expectedFaceLM = new int[] {
590                1, 2, 3, 4, 5, 6,
591                7, 8, 9, 10, 11, 12,
592                13, 14, 15, 16, 17, 18,
593                19, 20, 21, 22, 23, 24,
594                25, 26, 27, 28, 29, 30,
595        };
596        Point[] expectedFaceLMPoints = new Point[numFaces * 3];
597        for (int i = 0; i < numFaces; i++) {
598            expectedFaceLMPoints[i*3] = new Point(expectedFaceLM[i*6], expectedFaceLM[i*6+1]);
599            expectedFaceLMPoints[i*3+1] = new Point(expectedFaceLM[i*6+2], expectedFaceLM[i*6+3]);
600            expectedFaceLMPoints[i*3+2] = new Point(expectedFaceLM[i*6+4], expectedFaceLM[i*6+5]);
601        }
602
603        /**
604         * Read - FACE_DETECT_MODE == FULL
605         */
606        mMetadata.set(CaptureResult.STATISTICS_FACE_DETECT_MODE,
607                CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL);
608        mMetadata.set(CaptureResult.STATISTICS_FACE_IDS, expectedFaceIds);
609        mMetadata.set(CaptureResult.STATISTICS_FACE_SCORES, expectedFaceScores);
610        mMetadata.set(CaptureResult.STATISTICS_FACE_RECTANGLES, expectedRects);
611        mMetadata.set(CaptureResult.STATISTICS_FACE_LANDMARKS, expectedFaceLM);
612        Face[] resultFaces = mMetadata.get(CaptureResult.STATISTICS_FACES);
613        assertEquals(numFaces, resultFaces.length);
614        for (int i = 0; i < numFaces; i++) {
615            assertEquals(expectedFaceIds[i], resultFaces[i].getId());
616            assertEquals(expectedFaceScores[i], resultFaces[i].getScore());
617            assertEquals(expectedRects[i], resultFaces[i].getBounds());
618            assertEquals(expectedFaceLMPoints[i*3], resultFaces[i].getLeftEyePosition());
619            assertEquals(expectedFaceLMPoints[i*3+1], resultFaces[i].getRightEyePosition());
620            assertEquals(expectedFaceLMPoints[i*3+2], resultFaces[i].getMouthPosition());
621        }
622
623        /**
624         * Read - FACE_DETECT_MODE == SIMPLE
625         */
626        mMetadata.set(CaptureResult.STATISTICS_FACE_DETECT_MODE,
627                CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE);
628        mMetadata.set(CaptureResult.STATISTICS_FACE_SCORES, expectedFaceScores);
629        mMetadata.set(CaptureResult.STATISTICS_FACE_RECTANGLES, expectedRects);
630        Face[] resultSimpleFaces = mMetadata.get(CaptureResult.STATISTICS_FACES);
631        assertEquals(numFaces, resultSimpleFaces.length);
632        for (int i = 0; i < numFaces; i++) {
633            assertEquals(Face.ID_UNSUPPORTED, resultSimpleFaces[i].getId());
634            assertEquals(expectedFaceScores[i], resultSimpleFaces[i].getScore());
635            assertEquals(expectedRects[i], resultSimpleFaces[i].getBounds());
636            assertNull(resultSimpleFaces[i].getLeftEyePosition());
637            assertNull(resultSimpleFaces[i].getRightEyePosition());
638            assertNull(resultSimpleFaces[i].getMouthPosition());
639        }
640
641    }
642}
643