blob: 0c2f3a3abcc3622714fbae3540ab68a51ce7af55 [file] [log] [blame]
Igor Murashkin70725502013-06-25 20:27:06 +00001/*
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;
Igor Murashkinb519cc52013-07-02 11:23:44 -070021import android.graphics.ImageFormat;
Igor Murashkin70725502013-06-25 20:27:06 +000022import android.hardware.photography.CameraMetadata;
Igor Murashkinb519cc52013-07-02 11:23:44 -070023import 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;
Igor Murashkinb9dd6372013-07-11 19:37:04 -070030import java.nio.IntBuffer;
Igor Murashkinb519cc52013-07-02 11:23:44 -070031
32import static org.junit.Assert.assertArrayEquals;
Igor Murashkin70725502013-06-25 20:27:06 +000033
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
Igor Murashkinb519cc52013-07-02 11:23:44 -070046 // 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
Igor Murashkin70725502013-06-25 20:27:06 +000061 @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 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700134
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
Igor Murashkin70725502013-06-25 20:27:06 +0000439 }
Igor Murashkinb9dd6372013-07-11 19:37:04 -0700440
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,
Igor Murashkind7bf1772013-07-12 18:01:31 -0700487 AvailableFormat.IMPLEMENTATION_DEFINED,
488 AvailableFormat.YCbCr_420_888
Igor Murashkinb9dd6372013-07-11 19:37:04 -0700489 });
490
491 Key<AeAntibandingMode> availableFormatsKey =
492 new Key<AeAntibandingMode>("android.scaler.availableFormats",
493 AeAntibandingMode.class);
494 byte[] availableFormatValues = mMetadata.readValues(CameraMetadata
495 .getTag(availableFormatsKey.getName()));
496
497 int[] expectedIntValues = new int[] {
498 0x20,
499 0x32315659,
Igor Murashkind7bf1772013-07-12 18:01:31 -0700500 0x22,
501 0x23
Igor Murashkinb9dd6372013-07-11 19:37:04 -0700502 };
503
504 ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
505
506 assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
507 for (int i = 0; i < expectedIntValues.length; ++i) {
508 assertEquals(expectedIntValues[i], bf.getInt());
509 }
510 }
Igor Murashkin70725502013-06-25 20:27:06 +0000511}