Home | History | Annotate | Download | only in its
      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