• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package com.android.car;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.car.Car;
26 import android.car.drivingstate.CarDrivingStateEvent;
27 import android.car.drivingstate.CarDrivingStateManager;
28 import android.car.drivingstate.CarUxRestrictions;
29 import android.car.drivingstate.CarUxRestrictionsManager;
30 import android.hardware.automotive.vehicle.V2_0.VehicleGear;
31 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
32 import android.os.SystemClock;
33 import android.util.Log;
34 
35 import androidx.test.filters.SmallTest;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import com.android.car.vehiclehal.VehiclePropValueBuilder;
39 import com.android.internal.annotations.GuardedBy;
40 
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 @RunWith(AndroidJUnit4.class)
45 @SmallTest
46 public class CarDrivingRestrictionsTest extends MockedCarTestBase {
47     private static final String TAG = CarDrivingRestrictionsTest.class
48             .getSimpleName();
49     private CarDrivingStateManager mCarDrivingStateManager;
50     private CarUxRestrictionsManager mCarUxRManager;
51     // Currently set restrictions currently set in car_ux_restrictions_map.xml
52     private static final int UX_RESTRICTIONS_MOVING = CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD
53             | CarUxRestrictions.UX_RESTRICTIONS_NO_FILTERING
54             | CarUxRestrictions.UX_RESTRICTIONS_LIMIT_STRING_LENGTH
55             | CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD
56             | CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO
57             | CarUxRestrictions.UX_RESTRICTIONS_LIMIT_CONTENT
58             | CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP
59             | CarUxRestrictions.UX_RESTRICTIONS_NO_TEXT_MESSAGE;
60 
61 
62     @Override
configureMockedHal()63     protected synchronized void configureMockedHal() {
64         addProperty(VehicleProperty.PERF_VEHICLE_SPEED, VehiclePropValueBuilder
65                 .newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
66                 .addFloatValue(0f)
67                 .build());
68         addProperty(VehicleProperty.PARKING_BRAKE_ON, VehiclePropValueBuilder
69                 .newBuilder(VehicleProperty.PARKING_BRAKE_ON)
70                 .setBooleanValue(false)
71                 .build());
72         addProperty(VehicleProperty.GEAR_SELECTION, VehiclePropValueBuilder
73                 .newBuilder(VehicleProperty.GEAR_SELECTION)
74                 .addIntValue(0)
75                 .build());
76     }
77 
78     @Override
setUp()79     public void setUp() throws Exception {
80         super.setUp();
81         mCarDrivingStateManager = (CarDrivingStateManager) getCar()
82                 .getCarManager(Car.CAR_DRIVING_STATE_SERVICE);
83         mCarUxRManager = (CarUxRestrictionsManager) getCar()
84                 .getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
85     }
86 
87     @Test
testDrivingStateChange()88     public void testDrivingStateChange() throws InterruptedException {
89         CarDrivingStateEvent drivingEvent;
90         CarUxRestrictions restrictions;
91         DrivingStateListener listener = new DrivingStateListener();
92         mCarDrivingStateManager.registerListener(listener);
93         mCarUxRManager.registerListener(listener);
94         // With no gear value available, driving state should be unknown
95         listener.reset();
96         // Test Parked state and corresponding restrictions based on car_ux_restrictions_map.xml
97         Log.d(TAG, "Injecting gear park");
98         getMockedVehicleHal().injectEvent(
99                 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
100                         .addIntValue(VehicleGear.GEAR_PARK)
101                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
102                         .build());
103         drivingEvent = listener.waitForDrivingStateChange();
104         assertNotNull(drivingEvent);
105         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_PARKED);
106 
107         Log.d(TAG, "Injecting speed 0");
108         getMockedVehicleHal().injectEvent(
109                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
110                         .addFloatValue(0.0f)
111                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
112                         .build());
113 
114         // Switch gear to drive.  Driving state changes to Idling but the UX restrictions don't
115         // change between parked and idling.
116         listener.reset();
117         Log.d(TAG, "Injecting gear drive");
118         getMockedVehicleHal().injectEvent(
119                 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
120                         .addIntValue(VehicleGear.GEAR_DRIVE)
121                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
122                         .build());
123         drivingEvent = listener.waitForDrivingStateChange();
124         assertNotNull(drivingEvent);
125         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_IDLING);
126 
127         // Test Moving state and corresponding restrictions based on car_ux_restrictions_map.xml
128         listener.reset();
129         Log.d(TAG, "Injecting speed 30");
130         getMockedVehicleHal().injectEvent(
131                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
132                         .addFloatValue(30.0f)
133                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
134                         .build());
135         drivingEvent = listener.waitForDrivingStateChange();
136         assertNotNull(drivingEvent);
137         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_MOVING);
138         restrictions = listener.waitForUxRestrictionsChange();
139         assertNotNull(restrictions);
140         assertTrue(restrictions.isRequiresDistractionOptimization());
141         assertThat(restrictions.getActiveRestrictions()).isEqualTo(UX_RESTRICTIONS_MOVING);
142 
143         // Test Idling state and corresponding restrictions based on car_ux_restrictions_map.xml
144         listener.reset();
145         Log.d(TAG, "Injecting speed 0");
146         getMockedVehicleHal().injectEvent(
147                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
148                         .addFloatValue(0.0f)
149                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
150                         .build());
151         drivingEvent = listener.waitForDrivingStateChange();
152         assertNotNull(drivingEvent);
153         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_IDLING);
154         restrictions = listener.waitForUxRestrictionsChange();
155         assertNotNull(restrictions);
156         assertFalse(restrictions.isRequiresDistractionOptimization());
157         assertThat(restrictions.getActiveRestrictions())
158                 .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_BASELINE);
159 
160         // Apply Parking brake.  Supported gears is not provided in this test and hence
161         // Automatic transmission should be assumed and hence parking brake state should not
162         // make a difference to the driving state.
163         listener.reset();
164         Log.d(TAG, "Injecting parking brake on");
165         getMockedVehicleHal().injectEvent(
166                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
167                         .setBooleanValue(true)
168                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
169                         .build());
170         drivingEvent = listener.waitForDrivingStateChange();
171         assertNull(drivingEvent);
172 
173         mCarDrivingStateManager.unregisterListener();
174         mCarUxRManager.unregisterListener();
175     }
176 
177     @Test
testDrivingStateChangeForMalformedInputs()178     public void testDrivingStateChangeForMalformedInputs() throws InterruptedException {
179         CarDrivingStateEvent drivingEvent;
180         CarUxRestrictions restrictions;
181         DrivingStateListener listener = new DrivingStateListener();
182         mCarDrivingStateManager.registerListener(listener);
183         mCarUxRManager.registerListener(listener);
184 
185         // Start with gear = park and speed = 0 to begin with a known state.
186         listener.reset();
187         Log.d(TAG, "Injecting gear park");
188         getMockedVehicleHal().injectEvent(
189                 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
190                         .addIntValue(VehicleGear.GEAR_PARK)
191                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
192                         .build());
193         drivingEvent = listener.waitForDrivingStateChange();
194         assertNotNull(drivingEvent);
195         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_PARKED);
196 
197         Log.d(TAG, "Injecting speed 0");
198         getMockedVehicleHal().injectEvent(
199                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
200                         .addFloatValue(0.0f)
201                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
202                         .build());
203 
204         // Inject an invalid gear.  Since speed is still valid, idling will be the expected
205         // driving state
206         listener.reset();
207         Log.d(TAG, "Injecting gear -1");
208         getMockedVehicleHal().injectEvent(
209                 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
210                         .addIntValue(-1)
211                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
212                         .build());
213         drivingEvent = listener.waitForDrivingStateChange();
214         assertNotNull(drivingEvent);
215         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_IDLING);
216 
217         // Now, send in an invalid speed value as well, now the driving state will be unknown and
218         // the UX restrictions will change to fully restricted.
219         listener.reset();
220         Log.d(TAG, "Injecting speed -1");
221         getMockedVehicleHal().injectEvent(
222                 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
223                         .addFloatValue(-1.0f)
224                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
225                         .build());
226         drivingEvent = listener.waitForDrivingStateChange();
227         assertNotNull(drivingEvent);
228         assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
229         restrictions = listener.waitForUxRestrictionsChange();
230         assertNotNull(restrictions);
231         assertTrue(restrictions.isRequiresDistractionOptimization());
232         assertThat(restrictions.getActiveRestrictions())
233                 .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
234         mCarDrivingStateManager.unregisterListener();
235         mCarUxRManager.unregisterListener();
236     }
237 
238     /**
239      * Callback function we register for driving state update notifications.
240      */
241     private class DrivingStateListener implements
242             CarDrivingStateManager.CarDrivingStateEventListener,
243             CarUxRestrictionsManager.OnUxRestrictionsChangedListener {
244         private final Object mDrivingStateLock = new Object();
245         @GuardedBy("mDrivingStateLock")
246         private CarDrivingStateEvent mLastEvent = null;
247         private final Object mUxRLock = new Object();
248         @GuardedBy("mUxRLock")
249         private CarUxRestrictions mLastRestrictions = null;
250 
reset()251         void reset() {
252             mLastEvent = null;
253             mLastRestrictions = null;
254         }
255 
256         // Returns True to indicate receipt of a driving state event.  False indicates a timeout.
waitForDrivingStateChange()257         CarDrivingStateEvent waitForDrivingStateChange() throws InterruptedException {
258             long start = SystemClock.elapsedRealtime();
259 
260             synchronized (mDrivingStateLock) {
261                 while (mLastEvent == null
262                         && (start + DEFAULT_WAIT_TIMEOUT_MS > SystemClock.elapsedRealtime())) {
263                     mDrivingStateLock.wait(100L);
264                 }
265                 return mLastEvent;
266             }
267         }
268 
269         @Override
onDrivingStateChanged(CarDrivingStateEvent event)270         public void onDrivingStateChanged(CarDrivingStateEvent event) {
271             Log.d(TAG, "onDrivingStateChanged, event: " + event.eventValue);
272             synchronized (mDrivingStateLock) {
273                 // We're going to hold a reference to this object
274                 mLastEvent = event;
275                 mDrivingStateLock.notify();
276             }
277         }
278 
waitForUxRestrictionsChange()279         CarUxRestrictions waitForUxRestrictionsChange() throws InterruptedException {
280             long start = SystemClock.elapsedRealtime();
281             synchronized (mUxRLock) {
282                 while (mLastRestrictions == null
283                         && (start + DEFAULT_WAIT_TIMEOUT_MS > SystemClock.elapsedRealtime())) {
284                     mUxRLock.wait(100L);
285                 }
286             }
287             return mLastRestrictions;
288         }
289 
290         @Override
onUxRestrictionsChanged(CarUxRestrictions restrictions)291         public void onUxRestrictionsChanged(CarUxRestrictions restrictions) {
292             Log.d(TAG, "onUxRestrictionsChanged, restrictions: "
293                     + restrictions.getActiveRestrictions());
294             synchronized (mUxRLock) {
295                 mLastRestrictions = restrictions;
296                 mUxRLock.notify();
297             }
298         }
299     }
300 }
301