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 17 package com.android.cts.verifier.camera.its; 18 19 import android.graphics.Point; 20 import android.graphics.Rect; 21 import android.hardware.camera2.CameraCharacteristics; 22 import android.hardware.camera2.CameraDevice; 23 import android.hardware.camera2.CameraMetadata; 24 import android.hardware.camera2.CaptureResult; 25 import android.hardware.camera2.CaptureRequest; 26 import android.hardware.camera2.TotalCaptureResult; 27 import android.hardware.camera2.params.BlackLevelPattern; 28 import android.hardware.camera2.params.ColorSpaceTransform; 29 import android.hardware.camera2.params.Face; 30 import android.hardware.camera2.params.LensShadingMap; 31 import android.hardware.camera2.params.MeteringRectangle; 32 import android.hardware.camera2.params.RggbChannelVector; 33 import android.hardware.camera2.params.StreamConfigurationMap; 34 import android.hardware.camera2.params.TonemapCurve; 35 import android.location.Location; 36 import android.util.Log; 37 import android.util.Pair; 38 import android.util.Rational; 39 import android.util.Size; 40 import android.util.SizeF; 41 import android.util.Range; 42 43 import org.json.JSONArray; 44 import org.json.JSONObject; 45 46 import java.lang.reflect.Array; 47 import java.lang.reflect.Field; 48 import java.lang.reflect.GenericArrayType; 49 import java.lang.reflect.Modifier; 50 import java.lang.reflect.ParameterizedType; 51 import java.lang.reflect.Type; 52 import java.util.Arrays; 53 import java.util.LinkedList; 54 import java.util.List; 55 56 /** 57 * Class to deal with serializing and deserializing between JSON and Camera2 objects. 58 */ 59 public class ItsSerializer { 60 public static final String TAG = ItsSerializer.class.getSimpleName(); 61 62 private static class MetadataEntry { 63 public MetadataEntry(String k, Object v) { 64 key = k; 65 value = v; 66 } 67 public String key; 68 public Object value; 69 } 70 71 @SuppressWarnings("unchecked") 72 private static Object serializeRational(Rational rat) throws org.json.JSONException { 73 JSONObject ratObj = new JSONObject(); 74 ratObj.put("numerator", rat.getNumerator()); 75 ratObj.put("denominator", rat.getDenominator()); 76 return ratObj; 77 } 78 79 @SuppressWarnings("unchecked") 80 private static Object serializeSize(Size size) throws org.json.JSONException { 81 JSONObject sizeObj = new JSONObject(); 82 sizeObj.put("width", size.getWidth()); 83 sizeObj.put("height", size.getHeight()); 84 return sizeObj; 85 } 86 87 @SuppressWarnings("unchecked") 88 private static Object serializeSizeF(SizeF size) throws org.json.JSONException { 89 JSONObject sizeObj = new JSONObject(); 90 sizeObj.put("width", size.getWidth()); 91 sizeObj.put("height", size.getHeight()); 92 return sizeObj; 93 } 94 95 @SuppressWarnings("unchecked") 96 private static Object serializeRect(Rect rect) throws org.json.JSONException { 97 JSONObject rectObj = new JSONObject(); 98 rectObj.put("left", rect.left); 99 rectObj.put("right", rect.right); 100 rectObj.put("top", rect.top); 101 rectObj.put("bottom", rect.bottom); 102 return rectObj; 103 } 104 105 private static Object serializePoint(Point point) throws org.json.JSONException { 106 JSONObject pointObj = new JSONObject(); 107 pointObj.put("x", point.x); 108 pointObj.put("y", point.y); 109 return pointObj; 110 } 111 112 @SuppressWarnings("unchecked") 113 private static Object serializeFace(Face face) 114 throws org.json.JSONException { 115 JSONObject faceObj = new JSONObject(); 116 faceObj.put("bounds", serializeRect(face.getBounds())); 117 faceObj.put("score", face.getScore()); 118 faceObj.put("id", face.getId()); 119 faceObj.put("leftEye", serializePoint(face.getLeftEyePosition())); 120 faceObj.put("rightEye", serializePoint(face.getRightEyePosition())); 121 faceObj.put("mouth", serializePoint(face.getMouthPosition())); 122 return faceObj; 123 } 124 125 @SuppressWarnings("unchecked") 126 private static Object serializeStreamConfigurationMap( 127 StreamConfigurationMap map) 128 throws org.json.JSONException { 129 // TODO: Serialize the rest of the StreamConfigurationMap fields. 130 JSONObject mapObj = new JSONObject(); 131 JSONArray cfgArray = new JSONArray(); 132 int fmts[] = map.getOutputFormats(); 133 if (fmts != null) { 134 for (int fi = 0; fi < Array.getLength(fmts); fi++) { 135 Size sizes[] = map.getOutputSizes(fmts[fi]); 136 if (sizes != null) { 137 for (int si = 0; si < Array.getLength(sizes); si++) { 138 JSONObject obj = new JSONObject(); 139 obj.put("format", fmts[fi]); 140 obj.put("width",sizes[si].getWidth()); 141 obj.put("height", sizes[si].getHeight()); 142 obj.put("input", false); 143 obj.put("minFrameDuration", 144 map.getOutputMinFrameDuration(fmts[fi],sizes[si])); 145 cfgArray.put(obj); 146 } 147 } 148 } 149 } 150 mapObj.put("availableStreamConfigurations", cfgArray); 151 return mapObj; 152 } 153 154 @SuppressWarnings("unchecked") 155 private static Object serializeMeteringRectangle(MeteringRectangle rect) 156 throws org.json.JSONException { 157 JSONObject rectObj = new JSONObject(); 158 rectObj.put("x", rect.getX()); 159 rectObj.put("y", rect.getY()); 160 rectObj.put("width", rect.getWidth()); 161 rectObj.put("height", rect.getHeight()); 162 rectObj.put("weight", rect.getMeteringWeight()); 163 return rectObj; 164 } 165 166 @SuppressWarnings("unchecked") 167 private static Object serializePair(Pair pair) 168 throws org.json.JSONException { 169 JSONArray pairObj = new JSONArray(); 170 pairObj.put(pair.first); 171 pairObj.put(pair.second); 172 return pairObj; 173 } 174 175 @SuppressWarnings("unchecked") 176 private static Object serializeRange(Range range) 177 throws org.json.JSONException { 178 JSONArray rangeObj = new JSONArray(); 179 rangeObj.put(range.getLower()); 180 rangeObj.put(range.getUpper()); 181 return rangeObj; 182 } 183 184 @SuppressWarnings("unchecked") 185 private static Object serializeColorSpaceTransform(ColorSpaceTransform xform) 186 throws org.json.JSONException { 187 JSONArray xformObj = new JSONArray(); 188 for (int row = 0; row < 3; row++) { 189 for (int col = 0; col < 3; col++) { 190 xformObj.put(serializeRational(xform.getElement(col,row))); 191 } 192 } 193 return xformObj; 194 } 195 196 @SuppressWarnings("unchecked") 197 private static Object serializeTonemapCurve(TonemapCurve curve) 198 throws org.json.JSONException { 199 JSONObject curveObj = new JSONObject(); 200 String names[] = {"red", "green", "blue"}; 201 for (int ch = 0; ch < 3; ch++) { 202 JSONArray curveArr = new JSONArray(); 203 int len = curve.getPointCount(ch); 204 for (int i = 0; i < len; i++) { 205 curveArr.put(curve.getPoint(ch,i).x); 206 curveArr.put(curve.getPoint(ch,i).y); 207 } 208 curveObj.put(names[ch], curveArr); 209 } 210 return curveObj; 211 } 212 213 @SuppressWarnings("unchecked") 214 private static Object serializeRggbChannelVector(RggbChannelVector vec) 215 throws org.json.JSONException { 216 JSONArray vecObj = new JSONArray(); 217 vecObj.put(vec.getRed()); 218 vecObj.put(vec.getGreenEven()); 219 vecObj.put(vec.getGreenOdd()); 220 vecObj.put(vec.getBlue()); 221 return vecObj; 222 } 223 224 @SuppressWarnings("unchecked") 225 private static Object serializeBlackLevelPattern(BlackLevelPattern pat) 226 throws org.json.JSONException { 227 int patVals[] = new int[4]; 228 pat.copyTo(patVals, 0); 229 JSONArray patObj = new JSONArray(); 230 patObj.put(patVals[0]); 231 patObj.put(patVals[1]); 232 patObj.put(patVals[2]); 233 patObj.put(patVals[3]); 234 return patObj; 235 } 236 237 @SuppressWarnings("unchecked") 238 private static Object serializeLocation(Location loc) 239 throws org.json.JSONException { 240 return loc.toString(); 241 } 242 243 @SuppressWarnings("unchecked") 244 private static Object serializeLensShadingMap(LensShadingMap map) 245 throws org.json.JSONException { 246 JSONArray mapObj = new JSONArray(); 247 for (int row = 0; row < map.getRowCount(); row++) { 248 for (int col = 0; col < map.getColumnCount(); col++) { 249 for (int ch = 0; ch < 4; ch++) { 250 mapObj.put(map.getGainFactor(ch, col, row)); 251 } 252 } 253 } 254 return mapObj; 255 } 256 257 private static String getKeyName(Object keyObj) throws ItsException { 258 if (keyObj.getClass() == CaptureResult.Key.class 259 || keyObj.getClass() == TotalCaptureResult.class) { 260 return ((CaptureResult.Key)keyObj).getName(); 261 } else if (keyObj.getClass() == CaptureRequest.Key.class) { 262 return ((CaptureRequest.Key)keyObj).getName(); 263 } else if (keyObj.getClass() == CameraCharacteristics.Key.class) { 264 return ((CameraCharacteristics.Key)keyObj).getName(); 265 } 266 throw new ItsException("Invalid key object"); 267 } 268 269 private static Object getKeyValue(CameraMetadata md, Object keyObj) throws ItsException { 270 if (md.getClass() == CaptureResult.class || md.getClass() == TotalCaptureResult.class) { 271 return ((CaptureResult)md).get((CaptureResult.Key)keyObj); 272 } else if (md.getClass() == CaptureRequest.class) { 273 return ((CaptureRequest)md).get((CaptureRequest.Key)keyObj); 274 } else if (md.getClass() == CameraCharacteristics.class) { 275 return ((CameraCharacteristics)md).get((CameraCharacteristics.Key)keyObj); 276 } 277 throw new ItsException("Invalid key object"); 278 } 279 280 @SuppressWarnings("unchecked") 281 private static MetadataEntry serializeEntry(Type keyType, Object keyObj, CameraMetadata md) 282 throws ItsException { 283 String keyName = getKeyName(keyObj); 284 285 try { 286 Object keyValue = getKeyValue(md, keyObj); 287 if (keyValue == null) { 288 return new MetadataEntry(keyName, JSONObject.NULL); 289 } else if (keyType == Float.class) { 290 // The JSON serializer doesn't handle floating point NaN or Inf. 291 if (((Float)keyValue).isInfinite() || ((Float)keyValue).isNaN()) { 292 Logt.w(TAG, "Inf/NaN floating point value serialized: " + keyName); 293 return null; 294 } 295 return new MetadataEntry(keyName, keyValue); 296 } else if (keyType == Integer.class || keyType == Long.class || keyType == Byte.class || 297 keyType == Boolean.class || keyType == String.class) { 298 return new MetadataEntry(keyName, keyValue); 299 } else if (keyType == Rational.class) { 300 return new MetadataEntry(keyName, serializeRational((Rational)keyValue)); 301 } else if (keyType == Size.class) { 302 return new MetadataEntry(keyName, serializeSize((Size)keyValue)); 303 } else if (keyType == SizeF.class) { 304 return new MetadataEntry(keyName, serializeSizeF((SizeF)keyValue)); 305 } else if (keyType == Rect.class) { 306 return new MetadataEntry(keyName, serializeRect((Rect)keyValue)); 307 } else if (keyType == Face.class) { 308 return new MetadataEntry(keyName, serializeFace((Face)keyValue)); 309 } else if (keyType == StreamConfigurationMap.class) { 310 return new MetadataEntry(keyName, 311 serializeStreamConfigurationMap((StreamConfigurationMap)keyValue)); 312 } else if (keyType instanceof ParameterizedType && 313 ((ParameterizedType)keyType).getRawType() == Range.class) { 314 return new MetadataEntry(keyName, serializeRange((Range)keyValue)); 315 } else if (keyType == ColorSpaceTransform.class) { 316 return new MetadataEntry(keyName, 317 serializeColorSpaceTransform((ColorSpaceTransform)keyValue)); 318 } else if (keyType == MeteringRectangle.class) { 319 return new MetadataEntry(keyName, 320 serializeMeteringRectangle((MeteringRectangle)keyValue)); 321 } else if (keyType == Location.class) { 322 return new MetadataEntry(keyName, 323 serializeLocation((Location)keyValue)); 324 } else if (keyType == RggbChannelVector.class) { 325 return new MetadataEntry(keyName, 326 serializeRggbChannelVector((RggbChannelVector)keyValue)); 327 } else if (keyType == BlackLevelPattern.class) { 328 return new MetadataEntry(keyName, 329 serializeBlackLevelPattern((BlackLevelPattern)keyValue)); 330 } else if (keyType == TonemapCurve.class) { 331 return new MetadataEntry(keyName, 332 serializeTonemapCurve((TonemapCurve)keyValue)); 333 } else if (keyType == Point.class) { 334 return new MetadataEntry(keyName, 335 serializePoint((Point)keyValue)); 336 } else if (keyType == LensShadingMap.class) { 337 return new MetadataEntry(keyName, 338 serializeLensShadingMap((LensShadingMap)keyValue)); 339 } else { 340 Logt.w(TAG, String.format("Serializing unsupported key type: " + keyType)); 341 return null; 342 } 343 } catch (org.json.JSONException e) { 344 throw new ItsException("JSON error for key: " + keyName + ": ", e); 345 } 346 } 347 348 @SuppressWarnings("unchecked") 349 private static MetadataEntry serializeArrayEntry(Type keyType, Object keyObj, CameraMetadata md) 350 throws ItsException { 351 String keyName = getKeyName(keyObj); 352 try { 353 Object keyValue = getKeyValue(md, keyObj); 354 if (keyValue == null) { 355 return new MetadataEntry(keyName, JSONObject.NULL); 356 } 357 int arrayLen = Array.getLength(keyValue); 358 Type elmtType = ((GenericArrayType)keyType).getGenericComponentType(); 359 if (elmtType == int.class || elmtType == float.class || elmtType == byte.class || 360 elmtType == long.class || elmtType == double.class || elmtType == boolean.class) { 361 return new MetadataEntry(keyName, new JSONArray(keyValue)); 362 } else if (elmtType == Rational.class) { 363 JSONArray jsonArray = new JSONArray(); 364 for (int i = 0; i < arrayLen; i++) { 365 jsonArray.put(serializeRational((Rational)Array.get(keyValue,i))); 366 } 367 return new MetadataEntry(keyName, jsonArray); 368 } else if (elmtType == Size.class) { 369 JSONArray jsonArray = new JSONArray(); 370 for (int i = 0; i < arrayLen; i++) { 371 jsonArray.put(serializeSize((Size)Array.get(keyValue,i))); 372 } 373 return new MetadataEntry(keyName, jsonArray); 374 } else if (elmtType == Rect.class) { 375 JSONArray jsonArray = new JSONArray(); 376 for (int i = 0; i < arrayLen; i++) { 377 jsonArray.put(serializeRect((Rect)Array.get(keyValue,i))); 378 } 379 return new MetadataEntry(keyName, jsonArray); 380 } else if (elmtType == Face.class) { 381 JSONArray jsonArray = new JSONArray(); 382 for (int i = 0; i < arrayLen; i++) { 383 jsonArray.put(serializeFace((Face)Array.get(keyValue, i))); 384 } 385 return new MetadataEntry(keyName, jsonArray); 386 } else if (elmtType == StreamConfigurationMap.class) { 387 JSONArray jsonArray = new JSONArray(); 388 for (int i = 0; i < arrayLen; i++) { 389 jsonArray.put(serializeStreamConfigurationMap( 390 (StreamConfigurationMap)Array.get(keyValue,i))); 391 } 392 return new MetadataEntry(keyName, jsonArray); 393 } else if (elmtType instanceof ParameterizedType && 394 ((ParameterizedType)elmtType).getRawType() == Range.class) { 395 JSONArray jsonArray = new JSONArray(); 396 for (int i = 0; i < arrayLen; i++) { 397 jsonArray.put(serializeRange((Range)Array.get(keyValue,i))); 398 } 399 return new MetadataEntry(keyName, jsonArray); 400 } else if (elmtType instanceof ParameterizedType && 401 ((ParameterizedType)elmtType).getRawType() == Pair.class) { 402 JSONArray jsonArray = new JSONArray(); 403 for (int i = 0; i < arrayLen; i++) { 404 jsonArray.put(serializePair((Pair)Array.get(keyValue,i))); 405 } 406 return new MetadataEntry(keyName, jsonArray); 407 } else if (elmtType == MeteringRectangle.class) { 408 JSONArray jsonArray = new JSONArray(); 409 for (int i = 0; i < arrayLen; i++) { 410 jsonArray.put(serializeMeteringRectangle( 411 (MeteringRectangle)Array.get(keyValue,i))); 412 } 413 return new MetadataEntry(keyName, jsonArray); 414 } else if (elmtType == Location.class) { 415 JSONArray jsonArray = new JSONArray(); 416 for (int i = 0; i < arrayLen; i++) { 417 jsonArray.put(serializeLocation((Location)Array.get(keyValue,i))); 418 } 419 return new MetadataEntry(keyName, jsonArray); 420 } else if (elmtType == RggbChannelVector.class) { 421 JSONArray jsonArray = new JSONArray(); 422 for (int i = 0; i < arrayLen; i++) { 423 jsonArray.put(serializeRggbChannelVector( 424 (RggbChannelVector)Array.get(keyValue,i))); 425 } 426 return new MetadataEntry(keyName, jsonArray); 427 } else if (elmtType == BlackLevelPattern.class) { 428 JSONArray jsonArray = new JSONArray(); 429 for (int i = 0; i < arrayLen; i++) { 430 jsonArray.put(serializeBlackLevelPattern( 431 (BlackLevelPattern)Array.get(keyValue,i))); 432 } 433 return new MetadataEntry(keyName, jsonArray); 434 } else if (elmtType == Point.class) { 435 JSONArray jsonArray = new JSONArray(); 436 for (int i = 0; i < arrayLen; i++) { 437 jsonArray.put(serializePoint((Point)Array.get(keyValue,i))); 438 } 439 return new MetadataEntry(keyName, jsonArray); 440 } else { 441 Logt.w(TAG, String.format("Serializing unsupported array type: " + elmtType)); 442 return null; 443 } 444 } catch (org.json.JSONException e) { 445 throw new ItsException("JSON error for key: " + keyName + ": ", e); 446 } 447 } 448 449 @SuppressWarnings("unchecked") 450 public static JSONObject serialize(CameraMetadata md) 451 throws ItsException { 452 JSONObject jsonObj = new JSONObject(); 453 Field[] allFields = md.getClass().getDeclaredFields(); 454 if (md.getClass() == TotalCaptureResult.class) { 455 allFields = CaptureResult.class.getDeclaredFields(); 456 } 457 for (Field field : allFields) { 458 if (Modifier.isPublic(field.getModifiers()) && 459 Modifier.isStatic(field.getModifiers()) && 460 (field.getType() == CaptureRequest.Key.class 461 || field.getType() == CaptureResult.Key.class 462 || field.getType() == TotalCaptureResult.Key.class 463 || field.getType() == CameraCharacteristics.Key.class) && 464 field.getGenericType() instanceof ParameterizedType) { 465 ParameterizedType paramType = (ParameterizedType)field.getGenericType(); 466 Type[] argTypes = paramType.getActualTypeArguments(); 467 if (argTypes.length > 0) { 468 try { 469 Type keyType = argTypes[0]; 470 Object keyObj = field.get(md); 471 MetadataEntry entry; 472 if (keyType instanceof GenericArrayType) { 473 entry = serializeArrayEntry(keyType, keyObj, md); 474 } else { 475 entry = serializeEntry(keyType, keyObj, md); 476 } 477 478 // TODO: Figure this weird case out. 479 // There is a weird case where the entry is non-null but the toString 480 // of the entry is null, and if this happens, the null-ness spreads like 481 // a virus and makes the whole JSON object null from the top level down. 482 // Not sure if it's a bug in the library or I'm just not using it right. 483 // Workaround by checking for this case explicitly and not adding the 484 // value to the jsonObj when it is detected. 485 if (entry != null && entry.key != null && entry.value != null 486 && entry.value.toString() == null) { 487 Logt.w(TAG, "Error encountered serializing value for key: " + entry.key); 488 } else if (entry != null) { 489 jsonObj.put(entry.key, entry.value); 490 } else { 491 // Ignore. 492 } 493 } catch (IllegalAccessException e) { 494 throw new ItsException( 495 "Access error for field: " + field + ": ", e); 496 } catch (org.json.JSONException e) { 497 throw new ItsException( 498 "JSON error for field: " + field + ": ", e); 499 } 500 } 501 } 502 } 503 return jsonObj; 504 } 505 506 @SuppressWarnings("unchecked") 507 public static CaptureRequest.Builder deserialize(CaptureRequest.Builder mdDefault, 508 JSONObject jsonReq) throws ItsException { 509 try { 510 Logt.i(TAG, "Parsing JSON capture request ..."); 511 512 // Iterate over the CaptureRequest reflected fields. 513 CaptureRequest.Builder md = mdDefault; 514 Field[] allFields = CaptureRequest.class.getDeclaredFields(); 515 for (Field field : allFields) { 516 if (Modifier.isPublic(field.getModifiers()) && 517 Modifier.isStatic(field.getModifiers()) && 518 field.getType() == CaptureRequest.Key.class && 519 field.getGenericType() instanceof ParameterizedType) { 520 ParameterizedType paramType = (ParameterizedType)field.getGenericType(); 521 Type[] argTypes = paramType.getActualTypeArguments(); 522 if (argTypes.length > 0) { 523 CaptureRequest.Key key = (CaptureRequest.Key)field.get(md); 524 String keyName = key.getName(); 525 Type keyType = argTypes[0]; 526 527 // For each reflected CaptureRequest entry, look inside the JSON object 528 // to see if it is being set. If it is found, remove the key from the 529 // JSON object. After this process, there should be no keys left in the 530 // JSON (otherwise an invalid key was specified). 531 532 if (jsonReq.has(keyName) && !jsonReq.isNull(keyName)) { 533 if (keyType instanceof GenericArrayType) { 534 Type elmtType = 535 ((GenericArrayType)keyType).getGenericComponentType(); 536 JSONArray ja = jsonReq.getJSONArray(keyName); 537 Object val[] = new Object[ja.length()]; 538 for (int i = 0; i < ja.length(); i++) { 539 if (elmtType == int.class) { 540 Array.set(val, i, ja.getInt(i)); 541 } else if (elmtType == byte.class) { 542 Array.set(val, i, (byte)ja.getInt(i)); 543 } else if (elmtType == float.class) { 544 Array.set(val, i, (float)ja.getDouble(i)); 545 } else if (elmtType == long.class) { 546 Array.set(val, i, ja.getLong(i)); 547 } else if (elmtType == double.class) { 548 Array.set(val, i, ja.getDouble(i)); 549 } else if (elmtType == boolean.class) { 550 Array.set(val, i, ja.getBoolean(i)); 551 } else if (elmtType == String.class) { 552 Array.set(val, i, ja.getString(i)); 553 } else if (elmtType == Size.class){ 554 JSONObject obj = ja.getJSONObject(i); 555 Array.set(val, i, new Size( 556 obj.getInt("width"), obj.getInt("height"))); 557 } else if (elmtType == Rect.class) { 558 JSONObject obj = ja.getJSONObject(i); 559 Array.set(val, i, new Rect( 560 obj.getInt("left"), obj.getInt("top"), 561 obj.getInt("bottom"), obj.getInt("right"))); 562 } else if (elmtType == Rational.class) { 563 JSONObject obj = ja.getJSONObject(i); 564 Array.set(val, i, new Rational( 565 obj.getInt("numerator"), 566 obj.getInt("denominator"))); 567 } else if (elmtType == RggbChannelVector.class) { 568 JSONArray arr = ja.getJSONArray(i); 569 Array.set(val, i, new RggbChannelVector( 570 (float)arr.getDouble(0), 571 (float)arr.getDouble(1), 572 (float)arr.getDouble(2), 573 (float)arr.getDouble(3))); 574 } else if (elmtType == ColorSpaceTransform.class) { 575 JSONArray arr = ja.getJSONArray(i); 576 Rational xform[] = new Rational[9]; 577 for (int j = 0; j < 9; j++) { 578 xform[j] = new Rational( 579 arr.getJSONObject(j).getInt("numerator"), 580 arr.getJSONObject(j).getInt("denominator")); 581 } 582 Array.set(val, i, new ColorSpaceTransform(xform)); 583 } else if (elmtType == MeteringRectangle.class) { 584 JSONObject obj = ja.getJSONObject(i); 585 Array.set(val, i, new MeteringRectangle( 586 obj.getInt("x"), 587 obj.getInt("y"), 588 obj.getInt("width"), 589 obj.getInt("height"), 590 obj.getInt("weight"))); 591 } else { 592 throw new ItsException( 593 "Failed to parse key from JSON: " + keyName); 594 } 595 } 596 if (val != null) { 597 Logt.i(TAG, "Set: "+keyName+" -> "+Arrays.toString(val)); 598 md.set(key, val); 599 jsonReq.remove(keyName); 600 } 601 } else { 602 Object val = null; 603 if (keyType == Integer.class) { 604 val = jsonReq.getInt(keyName); 605 } else if (keyType == Byte.class) { 606 val = (byte)jsonReq.getInt(keyName); 607 } else if (keyType == Double.class) { 608 val = jsonReq.getDouble(keyName); 609 } else if (keyType == Long.class) { 610 val = jsonReq.getLong(keyName); 611 } else if (keyType == Float.class) { 612 val = (float)jsonReq.getDouble(keyName); 613 } else if (keyType == Boolean.class) { 614 val = jsonReq.getBoolean(keyName); 615 } else if (keyType == String.class) { 616 val = jsonReq.getString(keyName); 617 } else if (keyType == Size.class) { 618 JSONObject obj = jsonReq.getJSONObject(keyName); 619 val = new Size( 620 obj.getInt("width"), obj.getInt("height")); 621 } else if (keyType == Rect.class) { 622 JSONObject obj = jsonReq.getJSONObject(keyName); 623 val = new Rect( 624 obj.getInt("left"), obj.getInt("top"), 625 obj.getInt("right"), obj.getInt("bottom")); 626 } else if (keyType == Rational.class) { 627 JSONObject obj = jsonReq.getJSONObject(keyName); 628 val = new Rational(obj.getInt("numerator"), 629 obj.getInt("denominator")); 630 } else if (keyType == RggbChannelVector.class) { 631 JSONObject obj = jsonReq.optJSONObject(keyName); 632 JSONArray arr = jsonReq.optJSONArray(keyName); 633 if (arr != null) { 634 val = new RggbChannelVector( 635 (float)arr.getDouble(0), 636 (float)arr.getDouble(1), 637 (float)arr.getDouble(2), 638 (float)arr.getDouble(3)); 639 } else if (obj != null) { 640 val = new RggbChannelVector( 641 (float)obj.getDouble("red"), 642 (float)obj.getDouble("greenEven"), 643 (float)obj.getDouble("greenOdd"), 644 (float)obj.getDouble("blue")); 645 } else { 646 throw new ItsException("Invalid RggbChannelVector object"); 647 } 648 } else if (keyType == ColorSpaceTransform.class) { 649 JSONArray arr = jsonReq.getJSONArray(keyName); 650 Rational a[] = new Rational[9]; 651 for (int i = 0; i < 9; i++) { 652 a[i] = new Rational( 653 arr.getJSONObject(i).getInt("numerator"), 654 arr.getJSONObject(i).getInt("denominator")); 655 } 656 val = new ColorSpaceTransform(a); 657 } else if (keyType instanceof ParameterizedType && 658 ((ParameterizedType)keyType).getRawType() == Range.class && 659 ((ParameterizedType)keyType).getActualTypeArguments().length == 1 && 660 ((ParameterizedType)keyType).getActualTypeArguments()[0] == Integer.class) { 661 JSONArray arr = jsonReq.getJSONArray(keyName); 662 val = new Range<Integer>(arr.getInt(0), arr.getInt(1)); 663 } else { 664 throw new ItsException( 665 "Failed to parse key from JSON: " + 666 keyName + ", " + keyType); 667 } 668 if (val != null) { 669 Logt.i(TAG, "Set: " + keyName + " -> " + val); 670 md.set(key ,val); 671 jsonReq.remove(keyName); 672 } 673 } 674 } 675 } 676 } 677 } 678 679 // Ensure that there were no invalid keys in the JSON request object. 680 if (jsonReq.length() != 0) { 681 throw new ItsException("Invalid JSON key(s): " + jsonReq.toString()); 682 } 683 684 Logt.i(TAG, "Parsing JSON capture request completed"); 685 return md; 686 } catch (java.lang.IllegalAccessException e) { 687 throw new ItsException("Access error: ", e); 688 } catch (org.json.JSONException e) { 689 throw new ItsException("JSON error: ", e); 690 } 691 } 692 693 @SuppressWarnings("unchecked") 694 public static List<CaptureRequest.Builder> deserializeRequestList( 695 CameraDevice device, JSONObject jsonObjTop) 696 throws ItsException { 697 try { 698 List<CaptureRequest.Builder> requests = null; 699 JSONArray jsonReqs = jsonObjTop.getJSONArray("captureRequests"); 700 requests = new LinkedList<CaptureRequest.Builder>(); 701 for (int i = 0; i < jsonReqs.length(); i++) { 702 CaptureRequest.Builder templateReq = device.createCaptureRequest( 703 CameraDevice.TEMPLATE_STILL_CAPTURE); 704 requests.add( 705 deserialize(templateReq, jsonReqs.getJSONObject(i))); 706 } 707 return requests; 708 } catch (org.json.JSONException e) { 709 throw new ItsException("JSON error: ", e); 710 } catch (android.hardware.camera2.CameraAccessException e) { 711 throw new ItsException("Access error: ", e); 712 } 713 } 714 } 715