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