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.IAppFocus; 21 import android.car.ICar; 22 import android.car.ICarBluetooth; 23 import android.car.cluster.IInstrumentClusterManagerService; 24 import android.car.cluster.renderer.IInstrumentClusterNavigation; 25 import android.car.content.pm.ICarPackageManager; 26 import android.car.diagnostic.ICarDiagnostic; 27 import android.car.drivingstate.ICarDrivingState; 28 import android.car.drivingstate.ICarUxRestrictionsManager; 29 import android.car.hardware.power.ICarPower; 30 import android.car.media.ICarAudio; 31 import android.car.settings.ICarConfigurationManager; 32 import android.car.storagemonitoring.ICarStorageMonitoring; 33 import android.car.vms.IVmsSubscriberService; 34 import android.content.Context; 35 import android.os.IBinder; 36 import android.os.RemoteException; 37 import android.util.Log; 38 39 import org.mockito.Mock; 40 import org.mockito.MockitoAnnotations; 41 42 /* 43 The idea behind this class is that we can fake-out interfaces between Car*Manager and 44 Car Service. Effectively creating a fake version of Car Service that can run under Robolectric 45 environment (thus running on the desktop rather than on a real device). 46 47 By default all interfaces are mocked out just to allow dummy implementation and avoid crashes. 48 This will allow production code to call into Car*Manager w/o crashes because managers will just 49 pass the call into mocked version of the interface. However, in many cases 50 developers would like to have more sophisticated test cases and ability to simulate vehicle as 51 they need. In this case mocked version of particular service needs to be replaced with the fake 52 one which will have fake implementation to satisfy test needs and additional interface needs 53 to be exposed to the app developers such that they can simulate fake car behavior, this 54 interface has -Controller suffix and defined as inner interface in this class. 55 */ 56 57 /** 58 * Test API to get Car Managers backed by fake car service. 59 * 60 * <p>In order to use it in your tests you should create Car object by calling static method 61 * {@link FakeCar#createFakeCar(Context)}. It will effectively create {@link FakeCar} object and 62 * you can get access to {@link Car} by calling {@link FakeCar#getCar()}. Also, {@code FakeCar} 63 * provides additional testing API that will allow you to simulate vehicle's behavior as you need. 64 * 65 * <p>Here's an example of usage: 66 * <code> 67 * FakeCar fakeCar = FakeCar.createFakeCar(appContext); 68 * Car realCar = fakeCar.getCar(); // pass this instance to your DI framework or class to test 69 * 70 * // Then you can obtain different controllers to modify behavior of your fake car. 71 * PropertyController propertyController = fakeCar.getPropertyController(); 72 * propertyController.setProperties(listOfSupportedProperties) 73 * </code> 74 */ 75 public class FakeCar { 76 private static final String TAG = FakeCar.class.getSimpleName(); 77 78 private final Car mCar; 79 private final FakeCarService mService; 80 81 /** Creates an instance of {@link FakeCar} */ createFakeCar(Context context)82 public static FakeCar createFakeCar(Context context) { 83 FakeCarService service = new FakeCarService(context); 84 Car car = new Car(context, service, null); 85 86 return new FakeCar(car, service); 87 } 88 FakeCar(Car car, FakeCarService service)89 private FakeCar(Car car, FakeCarService service) { 90 mCar = car; 91 mService = service; 92 } 93 94 /** Returns Car object which is backed by fake implementation. */ getCar()95 public Car getCar() { 96 return mCar; 97 } 98 99 /** Returns test controller to modify car properties */ getCarPropertyController()100 public CarPropertyController getCarPropertyController() { 101 return mService.mCarProperty; 102 } 103 104 /** Returns test controller to change behavior of {@link android.car.CarProjectionManager} */ getCarProjectionController()105 public CarProjectionController getCarProjectionController() { 106 return mService.mCarProjection; 107 } 108 109 private static class FakeCarService extends ICar.Stub { 110 @Mock ICarAudio.Stub mCarAudio; 111 @Mock IAppFocus.Stub mAppFocus; 112 @Mock ICarPackageManager.Stub mCarPackageManager; 113 @Mock ICarDiagnostic.Stub mCarDiagnostic; 114 @Mock ICarPower.Stub mCarPower; 115 @Mock IInstrumentClusterNavigation.Stub mClusterNavigation; 116 @Mock IInstrumentClusterManagerService.Stub mClusterService; 117 @Mock IVmsSubscriberService.Stub mVmsSubscriberService; 118 @Mock ICarBluetooth.Stub mCarBluetooth; 119 @Mock ICarStorageMonitoring.Stub mCarStorageMonitoring; 120 @Mock ICarDrivingState.Stub mCarDrivingState; 121 @Mock ICarUxRestrictionsManager.Stub mCarUxRestriction; 122 @Mock ICarConfigurationManager.Stub mCarConfigurationManager; 123 124 private final FakeCarPropertyService mCarProperty; 125 private final FakeCarProjectionService mCarProjection; 126 FakeCarService(Context context)127 FakeCarService(Context context) { 128 MockitoAnnotations.initMocks(this); 129 mCarProperty = new FakeCarPropertyService(); 130 mCarProjection = new FakeCarProjectionService(context); 131 } 132 133 @Override setCarServiceHelper(IBinder helper)134 public void setCarServiceHelper(IBinder helper) throws RemoteException { 135 // Nothing to do yet. 136 } 137 138 @Override setUserLockStatus(int userHandle, int unlocked)139 public void setUserLockStatus(int userHandle, int unlocked) throws RemoteException { 140 // Nothing to do yet. 141 } 142 143 @Override onSwitchUser(int userHandle)144 public void onSwitchUser(int userHandle) throws RemoteException { 145 // Nothing to do yet. 146 } 147 148 @Override getCarService(String serviceName)149 public IBinder getCarService(String serviceName) throws RemoteException { 150 switch (serviceName) { 151 case Car.AUDIO_SERVICE: 152 return mCarAudio; 153 case Car.APP_FOCUS_SERVICE: 154 return mAppFocus; 155 case Car.PACKAGE_SERVICE: 156 return mCarPackageManager; 157 case Car.DIAGNOSTIC_SERVICE: 158 return mCarDiagnostic; 159 case Car.POWER_SERVICE: 160 return mCarPower; 161 case Car.CABIN_SERVICE: 162 case Car.HVAC_SERVICE: 163 case Car.INFO_SERVICE: 164 case Car.PROPERTY_SERVICE: 165 case Car.SENSOR_SERVICE: 166 case Car.VENDOR_EXTENSION_SERVICE: 167 return mCarProperty; 168 case Car.CAR_NAVIGATION_SERVICE: 169 return mClusterNavigation; 170 case Car.CAR_INSTRUMENT_CLUSTER_SERVICE: 171 return mClusterService; 172 case Car.PROJECTION_SERVICE: 173 return mCarProjection; 174 case Car.VMS_SUBSCRIBER_SERVICE: 175 return mVmsSubscriberService; 176 case Car.BLUETOOTH_SERVICE: 177 return mCarBluetooth; 178 case Car.STORAGE_MONITORING_SERVICE: 179 return mCarStorageMonitoring; 180 case Car.CAR_DRIVING_STATE_SERVICE: 181 return mCarDrivingState; 182 case Car.CAR_UX_RESTRICTION_SERVICE: 183 return mCarUxRestriction; 184 case Car.CAR_CONFIGURATION_SERVICE: 185 return mCarConfigurationManager; 186 default: 187 Log.w(TAG, "getCarService for unknown service:" + serviceName); 188 return null; 189 } 190 } 191 192 @Override getCarConnectionType()193 public int getCarConnectionType() throws RemoteException { 194 return Car.CONNECTION_TYPE_EMBEDDED; 195 } 196 } 197 198 } 199