• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.car.testapi;
18 
19 import static android.car.hardware.property.CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE;
20 
21 import static java.lang.Integer.toHexString;
22 
23 import android.annotation.Nullable;
24 import android.car.VehicleAreaType;
25 import android.car.VehiclePropertyType;
26 import android.car.hardware.CarPropertyConfig;
27 import android.car.hardware.CarPropertyValue;
28 import android.car.hardware.property.CarPropertyEvent;
29 import android.car.hardware.property.ICarProperty;
30 import android.car.hardware.property.ICarPropertyEventListener;
31 import android.os.RemoteException;
32 
33 import com.android.car.internal.PropertyPermissionMapping;
34 
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Set;
42 
43 /**
44  * This is fake implementation of the service which is used in
45  * {@link android.car.hardware.property.CarPropertyManager}.
46  *
47  * @hide
48  */
49 class FakeCarPropertyService extends ICarProperty.Stub implements CarPropertyController {
50     private final Map<Integer, CarPropertyConfig> mConfigs = new HashMap<>();
51     private final Map<PropKey, CarPropertyValue> mValues = new HashMap<>();
52 
53     private final PropertyPermissionMapping mPermissions = new PropertyPermissionMapping();
54 
55     // Contains a list of values that were set from the manager.
56     private final ArrayList<CarPropertyValue<?>> mValuesSet = new ArrayList<>();
57 
58     // Mapping between propertyId and a set of listeners.
59     private final Map<Integer, Set<ListenerInfo>> mListeners = new HashMap<>();
60 
61     @Override
registerListener(int propId, float rate, ICarPropertyEventListener listener)62     public void registerListener(int propId, float rate, ICarPropertyEventListener listener)
63             throws RemoteException {
64         Set<ListenerInfo> propListeners = mListeners.get(propId);
65         if (propListeners == null) {
66             propListeners = new HashSet<>();
67             mListeners.put(propId, propListeners);
68         }
69 
70         propListeners.add(new ListenerInfo(listener));
71     }
72 
73     @Override
unregisterListener(int propId, ICarPropertyEventListener listener)74     public void unregisterListener(int propId, ICarPropertyEventListener listener)
75             throws RemoteException {
76         Set<ListenerInfo> propListeners = mListeners.get(propId);
77         if (propListeners != null && propListeners.remove(new ListenerInfo(listener))) {
78             if (propListeners.isEmpty()) {
79                 mListeners.remove(propId);
80             }
81         }
82     }
83 
84     @Override
getPropertyList()85     public List<CarPropertyConfig> getPropertyList() throws RemoteException {
86         return new ArrayList<>(mConfigs.values());
87     }
88 
89     @Override
getPropertyConfigList(int[] propIds)90     public List<CarPropertyConfig> getPropertyConfigList(int[] propIds) {
91         List<CarPropertyConfig> configs = new ArrayList<>(propIds.length);
92         for (int prop : propIds) {
93             CarPropertyConfig cfg = mConfigs.get(prop);
94             if (cfg != null) {
95                 configs.add(cfg);
96             }
97         }
98         return configs;
99     }
100 
101     @Override
getProperty(int prop, int zone)102     public CarPropertyValue getProperty(int prop, int zone) throws RemoteException {
103         return mValues.get(PropKey.of(prop, zone));
104     }
105 
106     @Override
setProperty(CarPropertyValue prop, ICarPropertyEventListener listener)107     public void setProperty(CarPropertyValue prop, ICarPropertyEventListener listener)
108             throws RemoteException {
109         mValues.put(PropKey.of(prop), prop);
110         mValuesSet.add(prop);
111         sendEvent(prop);
112     }
113 
114     @Override
getReadPermission(int propId)115     public String getReadPermission(int propId) throws RemoteException {
116         return mConfigs.containsKey(propId) ? mPermissions.getReadPermission(propId) : null;
117     }
118 
119     @Override
getWritePermission(int propId)120     public String getWritePermission(int propId) throws RemoteException {
121         return mConfigs.containsKey(propId) ? mPermissions.getWritePermission(propId) : null;
122     }
123 
124     @Override
addProperty(Integer propId, Object value)125     public CarPropertyController addProperty(Integer propId, Object value) {
126         int areaType = getVehicleAreaType(propId);
127         Class<?> type = getPropertyType(propId);
128         CarPropertyConfig.Builder<?> builder = CarPropertyConfig
129                 .newBuilder(type, propId, areaType);
130         mConfigs.put(propId, builder.build());
131         if (value != null) {
132             updateValues(false, new CarPropertyValue<>(propId, 0, value));
133         }
134 
135         return this;
136     }
137 
138     @Override
addProperty(CarPropertyConfig<?> config, @Nullable CarPropertyValue<?> value)139     public CarPropertyController addProperty(CarPropertyConfig<?> config,
140             @Nullable CarPropertyValue<?> value) {
141         mConfigs.put(config.getPropertyId(), config);
142         if (value != null) {
143             updateValues(false, value);
144         }
145         return this;
146     }
147 
148     @Override
updateValues(boolean triggerListeners, CarPropertyValue<?>... propValues)149     public void updateValues(boolean triggerListeners, CarPropertyValue<?>... propValues) {
150         for (CarPropertyValue v : propValues) {
151             mValues.put(PropKey.of(v), v);
152             if (triggerListeners) {
153                 sendEvent(v);
154             }
155         }
156     }
157 
sendEvent(CarPropertyValue v)158     private void sendEvent(CarPropertyValue v) {
159         Set<ListenerInfo> listeners = mListeners.get(v.getPropertyId());
160         if (listeners != null) {
161             for (ListenerInfo listenerInfo : listeners) {
162                 List<CarPropertyEvent> events = new ArrayList<>();
163                 events.add(new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE, v));
164                 try {
165                     listenerInfo.mListener.onEvent(events);
166                 } catch (RemoteException e) {
167                     // This is impossible as the code runs within the same process in test.
168                     throw new RuntimeException(e);
169                 }
170             }
171         }
172     }
173 
174     @Override
getSetValues()175     public List<CarPropertyValue<?>> getSetValues() {
176         // Explicitly return the instance of this object rather than copying it such that test code
177         // will have a chance to clear this list if needed.
178         return mValuesSet;
179     }
180 
181     /** Consists of property id and area */
182     private static class PropKey {
183         final int mPropId;
184         final int mAreaId;
185 
PropKey(int propId, int areaId)186         private PropKey(int propId, int areaId) {
187             this.mPropId = propId;
188             this.mAreaId = areaId;
189         }
190 
of(int propId, int areaId)191         static PropKey of(int propId, int areaId) {
192             return new PropKey(propId, areaId);
193         }
194 
of(CarPropertyValue carPropertyValue)195         static PropKey of(CarPropertyValue carPropertyValue) {
196             return of(carPropertyValue.getPropertyId(), carPropertyValue.getAreaId());
197         }
198 
199         @Override
200 
equals(Object o)201         public boolean equals(Object o) {
202             if (this == o) {
203                 return true;
204             }
205             if (!(o instanceof PropKey)) {
206                 return false;
207             }
208             PropKey propKey = (PropKey) o;
209             return mPropId == propKey.mPropId && mAreaId == propKey.mAreaId;
210         }
211 
212         @Override
hashCode()213         public int hashCode() {
214             return Objects.hash(mPropId, mAreaId);
215         }
216     }
217 
218     private static class ListenerInfo {
219         private final ICarPropertyEventListener mListener;
220 
ListenerInfo(ICarPropertyEventListener listener)221         ListenerInfo(ICarPropertyEventListener listener) {
222             this.mListener = listener;
223         }
224 
225         @Override
equals(Object o)226         public boolean equals(Object o) {
227             if (this == o) {
228                 return true;
229             }
230             if (!(o instanceof ListenerInfo)) {
231                 return false;
232             }
233             ListenerInfo that = (ListenerInfo) o;
234             return Objects.equals(mListener, that.mListener);
235         }
236 
237         @Override
hashCode()238         public int hashCode() {
239             return Objects.hash(mListener);
240         }
241     }
242 
getPropertyType(int propId)243     private static Class<?> getPropertyType(int propId) {
244         int type = propId & VehiclePropertyType.MASK;
245         switch (type) {
246             case VehiclePropertyType.BOOLEAN:
247                 return Boolean.class;
248             case VehiclePropertyType.FLOAT:
249                 return Float.class;
250             case VehiclePropertyType.INT32:
251                 return Integer.class;
252             case VehiclePropertyType.INT64:
253                 return Long.class;
254             case VehiclePropertyType.FLOAT_VEC:
255                 return Float[].class;
256             case VehiclePropertyType.INT32_VEC:
257                 return Integer[].class;
258             case VehiclePropertyType.INT64_VEC:
259                 return Long[].class;
260             case VehiclePropertyType.STRING:
261                 return String.class;
262             case VehiclePropertyType.BYTES:
263                 return byte[].class;
264             case VehiclePropertyType.MIXED:
265                 return Object.class;
266             default:
267                 throw new IllegalArgumentException("Unexpected type: " + toHexString(type));
268         }
269     }
270 
getVehicleAreaType(int propId)271     private static int getVehicleAreaType(int propId) {
272         int halArea = propId & VehicleArea.MASK;
273         switch (halArea) {
274             case VehicleArea.GLOBAL:
275                 return VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
276             case VehicleArea.SEAT:
277                 return VehicleAreaType.VEHICLE_AREA_TYPE_SEAT;
278             case VehicleArea.DOOR:
279                 return VehicleAreaType.VEHICLE_AREA_TYPE_DOOR;
280             case VehicleArea.WINDOW:
281                 return VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW;
282             case VehicleArea.MIRROR:
283                 return VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR;
284             case VehicleArea.WHEEL:
285                 return VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL;
286             default:
287                 throw new RuntimeException("Unsupported area type " + halArea);
288         }
289     }
290 
291     /** Copy from VHAL generated file VehicleArea.java */
292     private static final class VehicleArea {
293         static final int GLOBAL = 16777216 /* 0x01000000 */;
294         static final int WINDOW = 50331648 /* 0x03000000 */;
295         static final int MIRROR = 67108864 /* 0x04000000 */;
296         static final int SEAT = 83886080 /* 0x05000000 */;
297         static final int DOOR = 100663296 /* 0x06000000 */;
298         static final int WHEEL = 117440512 /* 0x07000000 */;
299         static final int MASK = 251658240 /* 0x0f000000 */;
300     }
301 }
302