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