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