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