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