CameraMetadataTest.java revision b9dd637f830e6bd4f257ffb2c807c3ea27f8feee
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.ImageFormat;
22import android.hardware.photography.CameraMetadata;
23import android.hardware.photography.Rational;
24
25import static android.hardware.photography.CameraMetadata.*;
26
27import java.lang.reflect.Array;
28import java.nio.ByteBuffer;
29import java.nio.ByteOrder;
30import java.nio.IntBuffer;
31
32import static org.junit.Assert.assertArrayEquals;
33
34/**
35 * <pre>
36 * adb shell am instrument \
37 *      -e class 'com.android.mediaframeworktest.unit.CameraMetadataTest' \
38 *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
39 * </pre>
40 */
41public class CameraMetadataTest extends junit.framework.TestCase {
42
43    CameraMetadata mMetadata;
44    Parcel mParcel;
45
46    // Sections
47    static final int ANDROID_COLOR_CORRECTION = 0;
48    static final int ANDROID_CONTROL = 1;
49
50    // Section starts
51    static final int ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16;
52    static final int ANDROID_CONTROL_START = ANDROID_CONTROL << 16;
53
54    // Tags
55    static final int ANDROID_COLOR_CORRECTION_MODE = ANDROID_COLOR_CORRECTION_START;
56    static final int ANDROID_COLOR_CORRECTION_TRANSFORM = ANDROID_COLOR_CORRECTION_START + 1;
57
58    static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START;
59    static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1;
60
61    @Override
62    public void setUp() {
63        mMetadata = new CameraMetadata();
64        mParcel = Parcel.obtain();
65    }
66
67    @Override
68    public void tearDown() throws Exception {
69        mMetadata.close();
70        mMetadata = null;
71
72        mParcel.recycle();
73        mParcel = null;
74    }
75
76    @SmallTest
77    public void testNew() {
78        assertEquals(0, mMetadata.getEntryCount());
79        assertTrue(mMetadata.isEmpty());
80    }
81
82    @SmallTest
83    public void testClose() throws Exception {
84        mMetadata.isEmpty(); // no throw
85
86        assertFalse(mMetadata.isClosed());
87
88        mMetadata.close();
89
90        assertTrue(mMetadata.isClosed());
91
92        // OK: second close should not throw
93        mMetadata.close();
94
95        assertTrue(mMetadata.isClosed());
96
97        // All other calls after close should throw IllegalStateException
98
99        try {
100            mMetadata.isEmpty();
101            fail("Unreachable -- isEmpty after close should throw IllegalStateException");
102        } catch (IllegalStateException e) {
103            // good: we expect calling this method after close to fail
104        }
105
106        try {
107            mMetadata.getEntryCount();
108            fail("Unreachable -- getEntryCount after close should throw IllegalStateException");
109        } catch (IllegalStateException e) {
110            // good: we expect calling this method after close to fail
111        }
112
113
114        try {
115            mMetadata.swap(mMetadata);
116            fail("Unreachable -- swap after close should throw IllegalStateException");
117        } catch (IllegalStateException e) {
118         // good: we expect calling this method after close to fail
119        }
120
121        try {
122            mMetadata.readFromParcel(mParcel);
123            fail("Unreachable -- readFromParcel after close should throw IllegalStateException");
124        } catch (IllegalStateException e) {
125         // good: we expect calling this method after close to fail
126        }
127
128        try {
129            mMetadata.writeToParcel(mParcel, /*flags*/0);
130            fail("Unreachable -- writeToParcel after close should throw IllegalStateException");
131        } catch (IllegalStateException e) {
132         // good: we expect calling this method after close to fail
133        }
134
135        try {
136            mMetadata.readValues(/*tag*/0);
137            fail("Unreachable -- readValues after close should throw IllegalStateException");
138        } catch (IllegalStateException e) {
139         // good: we expect calling this method after close to fail
140        }
141
142        try {
143            mMetadata.writeValues(/*tag*/0, /*source*/new byte[] { 1,2,3 });
144            fail("Unreachable -- readValues after close should throw IllegalStateException");
145        } catch (IllegalStateException e) {
146         // good: we expect calling this method after close to fail
147        }
148    }
149
150    @SmallTest
151    public void testGetTagFromKey() {
152
153        // Test success
154
155        assertEquals(ANDROID_COLOR_CORRECTION_MODE,
156                CameraMetadata.getTag("android.colorCorrection.mode"));
157        assertEquals(ANDROID_COLOR_CORRECTION_TRANSFORM,
158                CameraMetadata.getTag("android.colorCorrection.transform"));
159        assertEquals(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
160                CameraMetadata.getTag("android.control.aeAntibandingMode"));
161        assertEquals(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
162                CameraMetadata.getTag("android.control.aeExposureCompensation"));
163
164        // Test failures
165
166        try {
167            CameraMetadata.getTag(null);
168            fail("A null key should throw NPE");
169        } catch(NullPointerException e) {
170        }
171
172        try {
173            CameraMetadata.getTag("android.control");
174            fail("A section name only should not be a valid key");
175        } catch(IllegalArgumentException e) {
176        }
177
178        try {
179            CameraMetadata.getTag("android.control.thisTagNameIsFakeAndDoesNotExist");
180            fail("A valid section with an invalid tag name should not be a valid key");
181        } catch(IllegalArgumentException e) {
182        }
183
184        try {
185            CameraMetadata.getTag("android");
186            fail("A namespace name only should not be a valid key");
187        } catch(IllegalArgumentException e) {
188        }
189
190        try {
191            CameraMetadata.getTag("this.key.is.definitely.invalid");
192            fail("A completely fake key name should not be valid");
193        } catch(IllegalArgumentException e) {
194        }
195    }
196
197    @SmallTest
198    public void testGetTypeFromTag() {
199        assertEquals(TYPE_BYTE, CameraMetadata.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
200        assertEquals(TYPE_FLOAT, CameraMetadata.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
201        assertEquals(TYPE_BYTE, CameraMetadata.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
202        assertEquals(TYPE_INT32,
203                CameraMetadata.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
204
205        try {
206            CameraMetadata.getNativeType(0xDEADF00D);
207            fail("No type should exist for invalid tag 0xDEADF00D");
208        } catch(IllegalArgumentException e) {
209        }
210    }
211
212    @SmallTest
213    public void testReadWriteValues() {
214        final byte ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
215        byte[] valueResult;
216
217        assertEquals(0, mMetadata.getEntryCount());
218        assertEquals(true, mMetadata.isEmpty());
219
220        //
221        // android.colorCorrection.mode (single enum byte)
222        //
223
224        assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
225
226        // Write 0 values
227        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {});
228
229        // Read 0 values
230        valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
231        assertNotNull(valueResult);
232        assertEquals(0, valueResult.length);
233
234        assertEquals(1, mMetadata.getEntryCount());
235        assertEquals(false, mMetadata.isEmpty());
236
237        // Write 1 value
238        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {
239            ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY
240        });
241
242        // Read 1 value
243        valueResult = mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE);
244        assertNotNull(valueResult);
245        assertEquals(1, valueResult.length);
246        assertEquals(ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY, valueResult[0]);
247
248        assertEquals(1, mMetadata.getEntryCount());
249        assertEquals(false, mMetadata.isEmpty());
250
251        //
252        // android.colorCorrection.transform (3x3 matrix)
253        //
254
255        final float[] transformMatrix = new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
256        byte[] transformMatrixAsByteArray = new byte[transformMatrix.length * 4];
257        ByteBuffer transformMatrixByteBuffer =
258                ByteBuffer.wrap(transformMatrixAsByteArray).order(ByteOrder.nativeOrder());
259        for (float f : transformMatrix)
260            transformMatrixByteBuffer.putFloat(f);
261
262        // Read
263        assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_TRANSFORM));
264        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_TRANSFORM, transformMatrixAsByteArray);
265
266        // Write
267        assertArrayEquals(transformMatrixAsByteArray,
268                mMetadata.readValues(ANDROID_COLOR_CORRECTION_TRANSFORM));
269
270        assertEquals(2, mMetadata.getEntryCount());
271        assertEquals(false, mMetadata.isEmpty());
272
273        // Erase
274        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_TRANSFORM, null);
275        assertNull(mMetadata.readValues(ANDROID_COLOR_CORRECTION_TRANSFORM));
276        assertEquals(1, mMetadata.getEntryCount());
277    }
278
279    private static <T> void assertArrayEquals(T expected, T actual) {
280        assertEquals(Array.getLength(expected), Array.getLength(actual));
281
282        int len = Array.getLength(expected);
283        for (int i = 0; i < len; ++i) {
284            assertEquals(Array.get(expected, i), Array.get(actual, i));
285        }
286    }
287
288    private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
289        Key<T> key = new Key<T>(keyStr, type);
290        assertNull(mMetadata.get(key));
291        mMetadata.set(key, value);
292        assertEquals(value, mMetadata.get(key));
293    }
294
295    private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
296        Key<T> key = new Key<T>(keyStr, type);
297        assertNull(mMetadata.get(key));
298        mMetadata.set(key, value);
299        assertArrayEquals(value, mMetadata.get(key));
300    }
301
302    @SmallTest
303    public void testReadWritePrimitive() {
304        // int32 (single)
305        checkKeyGetAndSet("android.control.aeExposureCompensation", Integer.TYPE, 0xC0FFEE);
306
307        // byte (single)
308        checkKeyGetAndSet("android.flash.maxEnergy", Byte.TYPE, (byte)6);
309
310        // int64 (single)
311        checkKeyGetAndSet("android.flash.firingTime", Long.TYPE, 0xABCD12345678FFFFL);
312
313        // float (single)
314        checkKeyGetAndSet("android.lens.aperture", Float.TYPE, Float.MAX_VALUE);
315
316        // double (single) -- technically double x 3, but we fake it
317        checkKeyGetAndSet("android.jpeg.gpsCoordinates", Double.TYPE, Double.MAX_VALUE);
318
319        // rational (single)
320        checkKeyGetAndSet("android.sensor.baseGainFactor", Rational.class, new Rational(1, 2));
321
322        /**
323         * Weirder cases, that don't map 1:1 with the native types
324         */
325
326        // bool (single) -- with TYPE_BYTE
327        checkKeyGetAndSet("android.control.aeLock", Boolean.TYPE, true);
328
329        // integer (single) -- with TYPE_BYTE
330        checkKeyGetAndSet("android.control.aePrecaptureTrigger", Integer.TYPE, 6);
331    }
332
333    @SmallTest
334    public void testReadWritePrimitiveArray() {
335        // int32 (n)
336        checkKeyGetAndSetArray("android.sensor.info.availableSensitivities", int[].class,
337                new int[] {
338                        0xC0FFEE, 0xDEADF00D
339                });
340
341        // byte (n)
342        checkKeyGetAndSetArray("android.statistics.faceScores", byte[].class, new byte[] {
343                1, 2, 3, 4
344        });
345
346        // int64 (n)
347        checkKeyGetAndSetArray("android.scaler.availableProcessedMinDurations", long[].class,
348                new long[] {
349                        0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
350                });
351
352        // float (n)
353        checkKeyGetAndSetArray("android.lens.info.availableApertures", float[].class,
354                new float[] {
355                        Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
356                });
357
358        // double (n) -- in particular double x 3
359        checkKeyGetAndSetArray("android.jpeg.gpsCoordinates", double[].class,
360                new double[] {
361                        Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
362                });
363
364        // rational (n) -- in particular rational x 9
365        checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
366                new Rational[] {
367                        new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
368                        new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
369                        new Rational(12, 13), new Rational(14, 15), new Rational(15, 16)
370                });
371
372        /**
373         * Weirder cases, that don't map 1:1 with the native types
374         */
375
376        // bool (n) -- with TYPE_BYTE
377        checkKeyGetAndSetArray("android.control.aeLock", boolean[].class, new boolean[] {
378                true, false, true
379        });
380
381
382        // integer (n) -- with TYPE_BYTE
383        checkKeyGetAndSetArray("android.control.aeAvailableModes", int[].class, new int[] {
384            1, 2, 3, 4
385        });
386    }
387
388    private enum ColorCorrectionMode {
389        TRANSFORM_MATRIX,
390        FAST,
391        HIGH_QUALITY
392    }
393
394    private enum AeAntibandingMode {
395        OFF,
396        _50HZ,
397        _60HZ,
398        AUTO
399    }
400
401    // TODO: special values for the enum.
402    private enum AvailableFormat {
403        RAW_SENSOR,
404        YV12,
405        YCrCb_420_SP,
406        IMPLEMENTATION_DEFINED,
407        YCbCr_420_888,
408        BLOB
409    }
410
411    @SmallTest
412    public void testReadWriteEnum() {
413        // byte (single)
414        checkKeyGetAndSet("android.colorCorrection.mode", ColorCorrectionMode.class,
415                ColorCorrectionMode.HIGH_QUALITY);
416
417        // byte (single)
418        checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
419                AeAntibandingMode.AUTO);
420
421        // byte (n)
422        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
423                AeAntibandingMode[].class, new AeAntibandingMode[] {
424                        AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
425                        AeAntibandingMode.AUTO
426                });
427
428        /**
429         * Stranger cases that don't use byte enums
430         */
431        // int (n)
432        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
433                new AvailableFormat[] {
434                        AvailableFormat.RAW_SENSOR,
435                        AvailableFormat.YV12,
436                        AvailableFormat.IMPLEMENTATION_DEFINED
437                });
438
439    }
440
441    @SmallTest
442    public void testReadWriteEnumWithCustomValues() {
443        CameraMetadata.registerEnumValues(AeAntibandingMode.class, new int[] {
444            0,
445            10,
446            20,
447            30
448        });
449
450        // byte (single)
451        checkKeyGetAndSet("android.control.aeAntibandingMode", AeAntibandingMode.class,
452                AeAntibandingMode.AUTO);
453
454        // byte (n)
455        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
456                AeAntibandingMode[].class, new AeAntibandingMode[] {
457                        AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
458                        AeAntibandingMode.AUTO
459                });
460
461        Key<AeAntibandingMode[]> aeAntibandingModeKey =
462                new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
463                        AeAntibandingMode[].class);
464        byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadata
465                .getTag("android.control.aeAvailableAntibandingModes"));
466        byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
467        assertArrayEquals(expectedValues, aeAntibandingModeValues);
468
469
470        /**
471         * Stranger cases that don't use byte enums
472         */
473        // int (n)
474        CameraMetadata.registerEnumValues(AvailableFormat.class, new int[] {
475            0x20,
476            0x32315659,
477            0x11,
478            0x22,
479            0x23,
480            0x21,
481        });
482
483        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
484                new AvailableFormat[] {
485                        AvailableFormat.RAW_SENSOR,
486                        AvailableFormat.YV12,
487                        AvailableFormat.IMPLEMENTATION_DEFINED
488                });
489
490        Key<AeAntibandingMode> availableFormatsKey =
491                new Key<AeAntibandingMode>("android.scaler.availableFormats",
492                        AeAntibandingMode.class);
493        byte[] availableFormatValues = mMetadata.readValues(CameraMetadata
494                .getTag(availableFormatsKey.getName()));
495
496        int[] expectedIntValues = new int[] {
497                0x20,
498                0x32315659,
499                0x22
500        };
501
502        ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
503
504        assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
505        for (int i = 0; i < expectedIntValues.length; ++i) {
506            assertEquals(expectedIntValues[i], bf.getInt());
507        }
508    }
509}
510