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