1 /* 2 * Copyright (C) 2016 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.car.vehiclehal.test; 18 19 import static java.lang.Integer.toHexString; 20 import static junit.framework.Assert.assertEquals; 21 import static junit.framework.Assert.assertNotNull; 22 import static junit.framework.Assert.fail; 23 24 import com.google.android.collect.Lists; 25 26 import android.hardware.automotive.vehicle.V2_0.IVehicle; 27 import android.hardware.automotive.vehicle.V2_0.IVehicleCallback; 28 import android.hardware.automotive.vehicle.V2_0.StatusCode; 29 import android.hardware.automotive.vehicle.V2_0.SubscribeOptions; 30 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 31 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 32 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess; 33 import android.os.RemoteException; 34 35 import java.util.ArrayList; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Map; 39 40 /** 41 * Mocked implementation of {@link IVehicle}. 42 */ 43 public class MockedVehicleHal extends IVehicle.Stub { 44 /** 45 * Interface for handler of each property. 46 */ 47 public interface VehicleHalPropertyHandler { 48 default void onPropertySet(VehiclePropValue value) {} 49 default VehiclePropValue onPropertyGet(VehiclePropValue value) { return null; } 50 default void onPropertySubscribe(int property, int zones, float sampleRate) {} 51 default void onPropertyUnsubscribe(int property) {} 52 53 VehicleHalPropertyHandler NOP = new VehicleHalPropertyHandler() {}; 54 } 55 56 private final Map<Integer, VehicleHalPropertyHandler> mPropertyHandlerMap = new HashMap<>(); 57 private final Map<Integer, VehiclePropConfig> mConfigs = new HashMap<>(); 58 private final Map<Integer, List<IVehicleCallback>> mSubscribers = new HashMap<>(); 59 60 public synchronized void addProperties(VehiclePropConfig... configs) { 61 for (VehiclePropConfig config : configs) { 62 addProperty(config, new DefaultPropertyHandler(config, null)); 63 } 64 } 65 66 public synchronized void addProperty(VehiclePropConfig config, 67 VehicleHalPropertyHandler handler) { 68 mPropertyHandlerMap.put(config.prop, handler); 69 mConfigs.put(config.prop, config); 70 } 71 72 public synchronized void addStaticProperty(VehiclePropConfig config, 73 VehiclePropValue value) { 74 addProperty(config, new StaticPropertyHandler(value)); 75 } 76 77 public synchronized void injectEvent(VehiclePropValue value) { 78 List<IVehicleCallback> callbacks = mSubscribers.get(value.prop); 79 assertNotNull("Injecting event failed for property: " + value.prop 80 + ". No listeners found", callbacks); 81 for (IVehicleCallback callback : callbacks) { 82 try { 83 callback.onPropertyEvent(Lists.newArrayList(value)); 84 } catch (RemoteException e) { 85 e.printStackTrace(); 86 fail("Remote exception while injecting events."); 87 } 88 } 89 } 90 91 public synchronized void injectError(int errorCode, int propertyId, int areaId) { 92 List<IVehicleCallback> callbacks = mSubscribers.get(propertyId); 93 assertNotNull("Injecting error failed for property: " + propertyId 94 + ". No listeners found", callbacks); 95 for (IVehicleCallback callback : callbacks) { 96 try { 97 callback.onPropertySetError(errorCode, propertyId, areaId); 98 } catch (RemoteException e) { 99 e.printStackTrace(); 100 fail("Remote exception while injecting errors."); 101 } 102 } 103 } 104 105 @Override 106 public synchronized ArrayList<VehiclePropConfig> getAllPropConfigs() { 107 return new ArrayList<>(mConfigs.values()); 108 } 109 110 @Override 111 public synchronized void getPropConfigs(ArrayList<Integer> props, getPropConfigsCallback cb) { 112 ArrayList<VehiclePropConfig> res = new ArrayList<>(); 113 for (Integer prop : props) { 114 VehiclePropConfig config = mConfigs.get(prop); 115 if (config == null) { 116 cb.onValues(StatusCode.INVALID_ARG, new ArrayList<>()); 117 return; 118 } 119 res.add(config); 120 } 121 cb.onValues(StatusCode.OK, res); 122 } 123 124 @Override 125 public synchronized void get(VehiclePropValue requestedPropValue, getCallback cb) { 126 VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(requestedPropValue.prop); 127 if (handler == null) { 128 cb.onValues(StatusCode.INVALID_ARG, null); 129 } else { 130 cb.onValues(StatusCode.OK, handler.onPropertyGet(requestedPropValue)); 131 } 132 } 133 134 @Override 135 public synchronized int set(VehiclePropValue propValue) { 136 VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propValue.prop); 137 if (handler == null) { 138 return StatusCode.INVALID_ARG; 139 } else { 140 handler.onPropertySet(propValue); 141 return StatusCode.OK; 142 } 143 } 144 145 @Override 146 public synchronized int subscribe(IVehicleCallback callback, 147 ArrayList<SubscribeOptions> options) { 148 for (SubscribeOptions opt : options) { 149 VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(opt.propId); 150 if (handler == null) { 151 return StatusCode.INVALID_ARG; 152 } 153 154 handler.onPropertySubscribe(opt.propId, opt.vehicleAreas, opt.sampleRate); 155 List<IVehicleCallback> subscribers = mSubscribers.get(opt.propId); 156 if (subscribers == null) { 157 subscribers = new ArrayList<>(); 158 mSubscribers.put(opt.propId, subscribers); 159 } 160 subscribers.add(callback); 161 } 162 return StatusCode.OK; 163 } 164 165 @Override 166 public synchronized int unsubscribe(IVehicleCallback callback, int propId) { 167 VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propId); 168 if (handler == null) { 169 return StatusCode.INVALID_ARG; 170 } 171 172 handler.onPropertyUnsubscribe(propId); 173 List<IVehicleCallback> subscribers = mSubscribers.get(propId); 174 if (subscribers != null) { 175 subscribers.remove(callback); 176 if (subscribers.size() == 0) { 177 mSubscribers.remove(propId); 178 } 179 } 180 return StatusCode.OK; 181 } 182 183 @Override 184 public String debugDump() { 185 return null; 186 } 187 188 public static class FailingPropertyHandler implements VehicleHalPropertyHandler { 189 @Override 190 public void onPropertySet(VehiclePropValue value) { 191 fail("Unexpected onPropertySet call"); 192 } 193 194 @Override 195 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 196 fail("Unexpected onPropertyGet call"); 197 return null; 198 } 199 200 @Override 201 public void onPropertySubscribe(int property, int zones, float sampleRate) { 202 fail("Unexpected onPropertySubscribe call"); 203 } 204 205 @Override 206 public void onPropertyUnsubscribe(int property) { 207 fail("Unexpected onPropertyUnsubscribe call"); 208 } 209 } 210 211 public static class StaticPropertyHandler extends FailingPropertyHandler { 212 private final VehiclePropValue mValue; 213 214 public StaticPropertyHandler(VehiclePropValue value) { 215 mValue = value; 216 } 217 218 @Override 219 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 220 return mValue; 221 } 222 } 223 224 public static class DefaultPropertyHandler implements VehicleHalPropertyHandler { 225 private final VehiclePropConfig mConfig; 226 private VehiclePropValue mValue; 227 private boolean mSubscribed = false; 228 229 public DefaultPropertyHandler(VehiclePropConfig config, VehiclePropValue initialValue) { 230 mConfig = config; 231 mValue = initialValue; 232 } 233 234 @Override 235 public synchronized void onPropertySet(VehiclePropValue value) { 236 assertEquals(mConfig.prop, value.prop); 237 assertEquals(VehiclePropertyAccess.WRITE, mConfig.access & VehiclePropertyAccess.WRITE); 238 mValue = value; 239 } 240 241 @Override 242 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 243 assertEquals(mConfig.prop, value.prop); 244 assertEquals(VehiclePropertyAccess.READ, mConfig.access & VehiclePropertyAccess.READ); 245 return mValue; 246 } 247 248 @Override 249 public synchronized void onPropertySubscribe(int property, int zones, float sampleRate) { 250 assertEquals(mConfig.prop, property); 251 mSubscribed = true; 252 } 253 254 @Override 255 public synchronized void onPropertyUnsubscribe(int property) { 256 assertEquals(mConfig.prop, property); 257 if (!mSubscribed) { 258 throw new IllegalArgumentException("Property was not subscribed 0x" 259 + toHexString( property)); 260 } 261 mSubscribed = false; 262 } 263 } 264 } 265