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.annotation.Nullable; 20 import android.car.Car; 21 import android.car.ICar; 22 import android.car.ICarResultReceiver; 23 import android.car.cluster.IInstrumentClusterManagerService; 24 import android.car.content.pm.ICarPackageManager; 25 import android.car.diagnostic.ICarDiagnostic; 26 import android.car.drivingstate.ICarDrivingState; 27 import android.car.hardware.power.ICarPower; 28 import android.car.storagemonitoring.ICarStorageMonitoring; 29 import android.content.Context; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.util.Log; 33 34 import com.android.car.internal.ICarServiceHelper; 35 36 import org.mockito.Mock; 37 import org.mockito.MockitoAnnotations; 38 39 import java.util.Collections; 40 import java.util.List; 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 placeholder 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 final 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 /** 110 * Returns the test controller to change the behavior of the underlying 111 * {@link android.car.CarAppFocusManager} 112 */ getAppFocusController()113 public CarAppFocusController getAppFocusController() { 114 return mService.mAppFocus; 115 } 116 117 /** 118 * Returns the test controller to change the behavior of as well as query the underlying {@link 119 * android.car.navigation.CarNavigationStatusManager}. 120 */ getCarNavigationStatusController()121 public CarNavigationStatusController getCarNavigationStatusController() { 122 return mService.mInstrumentClusterNavigation; 123 } 124 125 /** 126 * Returns a test controller that can modify and query the underlying service for the {@link 127 * android.car.drivingstate.CarUxRestrictionsManager}. 128 */ getCarUxRestrictionController()129 public CarUxRestrictionsController getCarUxRestrictionController() { 130 return mService.mCarUxRestrictionService; 131 } 132 133 private static class FakeCarService extends ICar.Stub { 134 @Mock ICarPackageManager.Stub mCarPackageManager; 135 @Mock ICarDiagnostic.Stub mCarDiagnostic; 136 @Mock ICarPower.Stub mCarPower; 137 @Mock IInstrumentClusterManagerService.Stub mClusterService; 138 @Mock ICarStorageMonitoring.Stub mCarStorageMonitoring; 139 @Mock ICarDrivingState.Stub mCarDrivingState; 140 141 private final FakeCarAudioService mCarAudio; 142 private final FakeAppFocusService mAppFocus; 143 private final FakeCarPropertyService mCarProperty; 144 private final FakeCarProjectionService mCarProjection; 145 private final FakeInstrumentClusterNavigation mInstrumentClusterNavigation; 146 private final FakeCarUxRestrictionsService mCarUxRestrictionService; 147 FakeCarService(Context context)148 FakeCarService(Context context) { 149 MockitoAnnotations.initMocks(this); 150 mCarAudio = new FakeCarAudioService(); 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 setSystemServerConnections(ICarServiceHelper helper, ICarResultReceiver receiver)159 public void setSystemServerConnections(ICarServiceHelper helper, 160 ICarResultReceiver receiver) 161 throws RemoteException { 162 // Nothing to do yet. 163 } 164 165 @Override 166 @Nullable getCarService(String serviceName)167 public IBinder getCarService(String serviceName) throws RemoteException { 168 switch (serviceName) { 169 case Car.AUDIO_SERVICE: 170 return mCarAudio; 171 case Car.APP_FOCUS_SERVICE: 172 return mAppFocus; 173 case Car.PACKAGE_SERVICE: 174 return mCarPackageManager; 175 case Car.DIAGNOSTIC_SERVICE: 176 return mCarDiagnostic; 177 case Car.POWER_SERVICE: 178 return mCarPower; 179 case Car.CABIN_SERVICE: 180 case Car.HVAC_SERVICE: 181 case Car.INFO_SERVICE: 182 case Car.PROPERTY_SERVICE: 183 case Car.SENSOR_SERVICE: 184 case Car.VENDOR_EXTENSION_SERVICE: 185 return mCarProperty; 186 case Car.CAR_NAVIGATION_SERVICE: 187 return mInstrumentClusterNavigation; 188 case Car.CAR_INSTRUMENT_CLUSTER_SERVICE: 189 return mClusterService; 190 case Car.PROJECTION_SERVICE: 191 return mCarProjection; 192 case Car.STORAGE_MONITORING_SERVICE: 193 return mCarStorageMonitoring; 194 case Car.CAR_DRIVING_STATE_SERVICE: 195 return mCarDrivingState; 196 case Car.CAR_UX_RESTRICTION_SERVICE: 197 return mCarUxRestrictionService; 198 default: 199 Log.w(TAG, "getCarService for unknown service:" + serviceName); 200 return null; 201 } 202 } 203 204 @Override getCarConnectionType()205 public int getCarConnectionType() throws RemoteException { 206 return Car.CONNECTION_TYPE_EMBEDDED; 207 } 208 209 @Override isFeatureEnabled(String featureName)210 public boolean isFeatureEnabled(String featureName) { 211 return false; 212 } 213 214 @Override enableFeature(String featureName)215 public int enableFeature(String featureName) { 216 return Car.FEATURE_REQUEST_SUCCESS; 217 } 218 219 @Override disableFeature(String featureName)220 public int disableFeature(String featureName) { 221 return Car.FEATURE_REQUEST_SUCCESS; 222 } 223 224 @Override getAllEnabledFeatures()225 public List<String> getAllEnabledFeatures() { 226 return Collections.emptyList(); 227 } 228 229 @Override getAllPendingDisabledFeatures()230 public List<String> getAllPendingDisabledFeatures() { 231 return Collections.emptyList(); 232 } 233 234 @Override getAllPendingEnabledFeatures()235 public List<String> getAllPendingEnabledFeatures() { 236 return Collections.emptyList(); 237 } 238 239 @Override getCarManagerClassForFeature(String featureName)240 public String getCarManagerClassForFeature(String featureName) { 241 return null; 242 } 243 } 244 245 } 246