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 android.car.Car; 20 import android.car.ICar; 21 import android.car.ICarBluetooth; 22 import android.car.cluster.IInstrumentClusterManagerService; 23 import android.car.content.pm.ICarPackageManager; 24 import android.car.diagnostic.ICarDiagnostic; 25 import android.car.drivingstate.ICarDrivingState; 26 import android.car.hardware.power.ICarPower; 27 import android.car.media.ICarAudio; 28 import android.car.settings.ICarConfigurationManager; 29 import android.car.storagemonitoring.ICarStorageMonitoring; 30 import android.content.Context; 31 import android.os.IBinder; 32 import android.os.RemoteException; 33 import android.util.Log; 34 35 import org.mockito.Mock; 36 import org.mockito.MockitoAnnotations; 37 38 import java.util.Collections; 39 import java.util.List; 40 41 /* 42 The idea behind this class is that we can fake-out interfaces between Car*Manager and 43 Car Service. Effectively creating a fake version of Car Service that can run under Robolectric 44 environment (thus running on the desktop rather than on a real device). 45 46 By default all interfaces are mocked out just to allow dummy implementation and avoid crashes. 47 This will allow production code to call into Car*Manager w/o crashes because managers will just 48 pass the call into mocked version of the interface. However, in many cases 49 developers would like to have more sophisticated test cases and ability to simulate vehicle as 50 they need. In this case mocked version of particular service needs to be replaced with the fake 51 one which will have fake implementation to satisfy test needs and additional interface needs 52 to be exposed to the app developers such that they can simulate fake car behavior, this 53 interface has -Controller suffix and defined as inner interface in this class. 54 */ 55 56 /** 57 * Test API to get Car Managers backed by fake car service. 58 * 59 * <p>In order to use it in your tests you should create Car object by calling static method 60 * {@link FakeCar#createFakeCar(Context)}. It will effectively create {@link FakeCar} object and 61 * you can get access to {@link Car} by calling {@link FakeCar#getCar()}. Also, {@code FakeCar} 62 * provides additional testing API that will allow you to simulate vehicle's behavior as you need. 63 * 64 * <p>Here's an example of usage: 65 * <code> 66 * FakeCar fakeCar = FakeCar.createFakeCar(appContext); 67 * Car realCar = fakeCar.getCar(); // pass this instance to your DI framework or class to test 68 * 69 * // Then you can obtain different controllers to modify behavior of your fake car. 70 * PropertyController propertyController = fakeCar.getPropertyController(); 71 * propertyController.setProperties(listOfSupportedProperties) 72 * </code> 73 */ 74 public class FakeCar { 75 private static final String TAG = FakeCar.class.getSimpleName(); 76 77 private final Car mCar; 78 private final FakeCarService mService; 79 80 /** Creates an instance of {@link FakeCar} */ createFakeCar(Context context)81 public static FakeCar createFakeCar(Context context) { 82 FakeCarService service = new FakeCarService(context); 83 Car car = new Car(context, service, null); 84 85 return new FakeCar(car, service); 86 } 87 FakeCar(Car car, FakeCarService service)88 private FakeCar(Car car, FakeCarService service) { 89 mCar = car; 90 mService = service; 91 } 92 93 /** Returns Car object which is backed by fake implementation. */ getCar()94 public Car getCar() { 95 return mCar; 96 } 97 98 /** Returns test controller to modify car properties */ getCarPropertyController()99 public CarPropertyController getCarPropertyController() { 100 return mService.mCarProperty; 101 } 102 103 /** Returns test controller to change behavior of {@link android.car.CarProjectionManager} */ getCarProjectionController()104 public CarProjectionController getCarProjectionController() { 105 return mService.mCarProjection; 106 } 107 108 /** 109 * Returns the test controller to change the behavior of the underlying 110 * {@link android.car.CarAppFocusManager} 111 */ getAppFocusController()112 public CarAppFocusController getAppFocusController() { 113 return mService.mAppFocus; 114 } 115 116 /** 117 * Returns the test controller to change the behavior of as well as query the underlying {@link 118 * android.car.navigation.CarNavigationStatusManager}. 119 */ getCarNavigationStatusController()120 public CarNavigationStatusController getCarNavigationStatusController() { 121 return mService.mInstrumentClusterNavigation; 122 } 123 124 /** 125 * Returns a test controller that can modify and query the underlying service for the {@link 126 * android.car.drivingstate.CarUxRestrictionsManager}. 127 */ getCarUxRestrictionController()128 public CarUxRestrictionsController getCarUxRestrictionController() { 129 return mService.mCarUxRestrictionService; 130 } 131 132 private static class FakeCarService extends ICar.Stub { 133 @Mock ICarAudio.Stub mCarAudio; 134 @Mock ICarPackageManager.Stub mCarPackageManager; 135 @Mock ICarDiagnostic.Stub mCarDiagnostic; 136 @Mock ICarPower.Stub mCarPower; 137 @Mock IInstrumentClusterManagerService.Stub mClusterService; 138 @Mock ICarBluetooth.Stub mCarBluetooth; 139 @Mock ICarStorageMonitoring.Stub mCarStorageMonitoring; 140 @Mock ICarDrivingState.Stub mCarDrivingState; 141 @Mock ICarConfigurationManager.Stub mCarConfigurationManager; 142 143 private final FakeAppFocusService mAppFocus; 144 private final FakeCarPropertyService mCarProperty; 145 private final FakeCarProjectionService mCarProjection; 146 private final FakeInstrumentClusterNavigation mInstrumentClusterNavigation; 147 private final FakeCarUxRestrictionsService mCarUxRestrictionService; 148 FakeCarService(Context context)149 FakeCarService(Context context) { 150 MockitoAnnotations.initMocks(this); 151 mAppFocus = new FakeAppFocusService(context); 152 mCarProperty = new FakeCarPropertyService(); 153 mCarProjection = new FakeCarProjectionService(context); 154 mInstrumentClusterNavigation = new FakeInstrumentClusterNavigation(); 155 mCarUxRestrictionService = new FakeCarUxRestrictionsService(); 156 } 157 158 @Override setCarServiceHelper(IBinder helper)159 public void setCarServiceHelper(IBinder helper) throws RemoteException { 160 // Nothing to do yet. 161 } 162 163 @Override onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId, int toUserId)164 public void onUserLifecycleEvent(int eventType, long timestampMs, int fromUserId, 165 int toUserId) { 166 // Nothing to do yet. 167 } 168 169 @Override onFirstUserUnlocked(int userId, long timestampMs, long duration, int halResponseTime)170 public void onFirstUserUnlocked(int userId, long timestampMs, long duration, 171 int halResponseTime) { 172 // Nothing to do yet. 173 } 174 175 @Override getInitialUserInfo(int requestType, int timeoutMs, IBinder binder)176 public void getInitialUserInfo(int requestType, int timeoutMs, IBinder binder) { 177 // Nothing to do yet. 178 } 179 180 @Override setInitialUser(int userId)181 public void setInitialUser(int userId) { 182 // Nothing to do yet. 183 } 184 185 @Override getCarService(String serviceName)186 public IBinder getCarService(String serviceName) throws RemoteException { 187 switch (serviceName) { 188 case Car.AUDIO_SERVICE: 189 return mCarAudio; 190 case Car.APP_FOCUS_SERVICE: 191 return mAppFocus; 192 case Car.PACKAGE_SERVICE: 193 return mCarPackageManager; 194 case Car.DIAGNOSTIC_SERVICE: 195 return mCarDiagnostic; 196 case Car.POWER_SERVICE: 197 return mCarPower; 198 case Car.CABIN_SERVICE: 199 case Car.HVAC_SERVICE: 200 case Car.INFO_SERVICE: 201 case Car.PROPERTY_SERVICE: 202 case Car.SENSOR_SERVICE: 203 case Car.VENDOR_EXTENSION_SERVICE: 204 return mCarProperty; 205 case Car.CAR_NAVIGATION_SERVICE: 206 return mInstrumentClusterNavigation; 207 case Car.CAR_INSTRUMENT_CLUSTER_SERVICE: 208 return mClusterService; 209 case Car.PROJECTION_SERVICE: 210 return mCarProjection; 211 case Car.BLUETOOTH_SERVICE: 212 return mCarBluetooth; 213 case Car.STORAGE_MONITORING_SERVICE: 214 return mCarStorageMonitoring; 215 case Car.CAR_DRIVING_STATE_SERVICE: 216 return mCarDrivingState; 217 case Car.CAR_UX_RESTRICTION_SERVICE: 218 return mCarUxRestrictionService; 219 case Car.CAR_CONFIGURATION_SERVICE: 220 return mCarConfigurationManager; 221 default: 222 Log.w(TAG, "getCarService for unknown service:" + serviceName); 223 return null; 224 } 225 } 226 227 @Override getCarConnectionType()228 public int getCarConnectionType() throws RemoteException { 229 return Car.CONNECTION_TYPE_EMBEDDED; 230 } 231 232 @Override isFeatureEnabled(String featureName)233 public boolean isFeatureEnabled(String featureName) { 234 return false; 235 } 236 237 @Override enableFeature(String featureName)238 public int enableFeature(String featureName) { 239 return Car.FEATURE_REQUEST_SUCCESS; 240 } 241 242 @Override disableFeature(String featureName)243 public int disableFeature(String featureName) { 244 return Car.FEATURE_REQUEST_SUCCESS; 245 } 246 247 @Override getAllEnabledFeatures()248 public List<String> getAllEnabledFeatures() { 249 return Collections.emptyList(); 250 } 251 252 @Override getAllPendingDisabledFeatures()253 public List<String> getAllPendingDisabledFeatures() { 254 return Collections.emptyList(); 255 } 256 257 @Override getAllPendingEnabledFeatures()258 public List<String> getAllPendingEnabledFeatures() { 259 return Collections.emptyList(); 260 } 261 262 @Override getCarManagerClassForFeature(String featureName)263 public String getCarManagerClassForFeature(String featureName) { 264 return null; 265 } 266 } 267 268 } 269