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