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