1 /*
2  * Copyright (C) 2018 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 package com.android.car.vehiclehal.test;
17 
18 import static java.lang.Integer.toHexString;
19 
20 import android.car.hardware.CarPropertyValue;
21 import android.hardware.automotive.vehicle.VehiclePropertyType;
22 
23 import org.json.JSONArray;
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 
27 import java.io.BufferedReader;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.InputStreamReader;
31 import java.nio.charset.StandardCharsets;
32 import java.util.ArrayList;
33 import java.util.List;
34 
35 
36 class VhalJsonReader {
37 
38     /**
39      * Name of fields presented in JSON file. All of them are required.
40      */
41     private static final String JSON_FIELD_PROP = "prop";
42     private static final String JSON_FIELD_AREA_ID = "areaId";
43     private static final String JSON_FIELD_TIMESTAMP = "timestamp";
44     private static final String JSON_FIELD_VALUE = "value";
45     private static final String JSON_FIELD_INT32_VALUES = "int32Values";
46     private static final String JSON_FIELD_INT64_VALUES = "int64Values";
47     private static final String JSON_FIELD_FLOAT_VALUES = "floatValues";
48     private static final String JSON_FIELD_STRING_VALUE = "stringValue";
49 
readFromJson(InputStream in)50     public static List<CarPropertyValue> readFromJson(InputStream in)
51             throws IOException, JSONException {
52         JSONArray rawEvents = new JSONArray(readJsonString(in));
53         List<CarPropertyValue> events = new ArrayList<>();
54         for (int i = 0; i < rawEvents.length(); i++) {
55             events.add(getEvent(rawEvents.getJSONObject(i)));
56         }
57         return events;
58     }
59 
readJsonString(InputStream in)60     private static String readJsonString(InputStream in) throws IOException {
61         StringBuilder builder = new StringBuilder();
62         try (BufferedReader reader = new BufferedReader(
63                 new InputStreamReader(in, StandardCharsets.UTF_8))) {
64             reader.lines().forEach(builder::append);
65         }
66         return builder.toString();
67     }
68 
getEvent(JSONObject rawEvent)69     private static CarPropertyValue<?> getEvent(JSONObject rawEvent) throws JSONException {
70         int prop = rawEvent.getInt(JSON_FIELD_PROP);
71         int areaId = rawEvent.getInt(JSON_FIELD_AREA_ID);
72         long timestamp = rawEvent.getLong(JSON_FIELD_TIMESTAMP);
73 
74         switch (prop & VehiclePropertyType.MASK) {
75             case VehiclePropertyType.BOOLEAN:
76                 return new CarPropertyValue<>(prop, areaId, CarPropertyValue.STATUS_AVAILABLE,
77                                             timestamp, rawEvent.getInt(JSON_FIELD_VALUE) != 0);
78             case VehiclePropertyType.INT32:
79                 return new CarPropertyValue<>(prop, areaId, CarPropertyValue.STATUS_AVAILABLE,
80                                             timestamp, rawEvent.getInt(JSON_FIELD_VALUE));
81             case VehiclePropertyType.INT64:
82                 return new CarPropertyValue<>(prop, areaId, CarPropertyValue.STATUS_AVAILABLE,
83                                             timestamp, rawEvent.getLong(JSON_FIELD_VALUE));
84             case VehiclePropertyType.FLOAT:
85                 return new CarPropertyValue<>(prop, areaId,
86                                               CarPropertyValue.STATUS_AVAILABLE, timestamp,
87                                               (float) rawEvent.getDouble(JSON_FIELD_VALUE));
88             case VehiclePropertyType.STRING:
89                 return new CarPropertyValue<>(prop, areaId, CarPropertyValue.STATUS_AVAILABLE,
90                                             timestamp, rawEvent.getString(JSON_FIELD_VALUE));
91             // TODO: CarPropertyValue API has not supported VehiclePropertyType.MIXED type yet.
92             // Here is a temporary solution to use VehiclePropValue.RawValue
93             case VehiclePropertyType.MIXED:
94                 List<Object> valuesList = new ArrayList<>();
95                 JSONObject rawValueJson = rawEvent.getJSONObject(JSON_FIELD_VALUE);
96 
97                 copyValuesArray(valuesList, rawValueJson.optJSONArray(JSON_FIELD_INT32_VALUES),
98                         Integer.class);
99                 copyValuesArray(valuesList, rawValueJson.optJSONArray(JSON_FIELD_INT64_VALUES),
100                         Long.class);
101                 copyValuesArray(valuesList, rawValueJson.optJSONArray(JSON_FIELD_FLOAT_VALUES),
102                         Float.class);
103                 valuesList.add(rawValueJson.getString(JSON_FIELD_STRING_VALUE));
104 
105                 return new CarPropertyValue<>(prop, areaId, CarPropertyValue.STATUS_AVAILABLE,
106                                               timestamp, valuesList.toArray());
107             default:
108                 throw new IllegalArgumentException("Property type 0x"
109                         + toHexString(prop & VehiclePropertyType.MASK)
110                         + " is not supported in the test.");
111         }
112     }
113 
copyValuesArray(List valuesList, JSONArray jsonArray, Class clazz)114     private static void copyValuesArray(List valuesList, JSONArray jsonArray, Class clazz)
115             throws JSONException {
116         if (jsonArray == null) {
117             return;
118         }
119         for (int i = 0; i < jsonArray.length(); i++) {
120             if (clazz == Integer.class) {
121                 valuesList.add(jsonArray.getInt(i));
122             } else if (clazz == Long.class) {
123                 valuesList.add(jsonArray.getLong(i));
124             } else if (clazz == Float.class) {
125                 valuesList.add((float) jsonArray.getDouble(i));
126             }
127         }
128     }
129 }
130