blob: 945d5544341426c0f60bd8d2cca8f1c541b4fcc0 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car;
import android.car.Car;
import android.car.VehicleAreaType;
import android.car.VehiclePropertyIds;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.property.CarPropertyManager;
import android.hardware.automotive.vehicle.V2_0.VehicleArea;
import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
import android.os.SystemClock;
import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
* Test for {@link android.car.hardware.property.CarPropertyManager}
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
public class CarPropertyManagerTest extends MockedCarTestBase {
private static final String TAG = CarPropertyManagerTest.class.getSimpleName();
/**
* configArray[0], 1 indicates the property has a String value
* configArray[1], 1 indicates the property has a Boolean value .
* configArray[2], 1 indicates the property has a Integer value
* configArray[3], the number indicates the size of Integer[] in the property.
* configArray[4], 1 indicates the property has a Long value .
* configArray[5], the number indicates the size of Long[] in the property.
* configArray[6], 1 indicates the property has a Float value .
* configArray[7], the number indicates the size of Float[] in the property.
* configArray[8], the number indicates the size of byte[] in the property.
*/
private static final java.util.Collection<Integer> CONFIG_ARRAY_1 =
Arrays.asList(1, 0, 1, 0, 1, 0, 0, 0, 0);
private static final java.util.Collection<Integer> CONFIG_ARRAY_2 =
Arrays.asList(1, 1, 1, 0, 0, 0, 0, 2, 0);
private static final Object[] EXPECTED_VALUE_1 = {"android", 1, 1L};
private static final Object[] EXPECTED_VALUE_2 = {"android", true, 3, 1.1f, 2f};
private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_1 =
0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.SEAT;
private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_2 =
0x1102 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL;
// Use FAKE_PROPERTY_ID to test api return null or throw exception.
private static final int FAKE_PROPERTY_ID = 0x111;
private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT
| VehicleAreaSeat.ROW_2_LEFT;
private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT
| VehicleAreaSeat.ROW_2_CENTER
| VehicleAreaSeat.ROW_2_RIGHT;
private static final float INIT_TEMP_VALUE = 16f;
private static final float CHANGED_TEMP_VALUE = 20f;
private CarPropertyManager mManager;
@Override
public void setUp() throws Exception {
super.setUp();
mManager = (CarPropertyManager) getCar().getCarManager(Car.PROPERTY_SERVICE);
Assert.assertNotNull(mManager);
}
@Test
public void testMixedPropertyConfigs() {
List<CarPropertyConfig> configs = mManager.getPropertyList();
Assert.assertEquals(3, configs.size());
for (CarPropertyConfig cfg : configs) {
switch (cfg.getPropertyId()) {
case CUSTOM_GLOBAL_MIXED_PROP_ID_1:
Assert.assertArrayEquals(CONFIG_ARRAY_1.toArray(),
cfg.getConfigArray().toArray());
break;
case CUSTOM_GLOBAL_MIXED_PROP_ID_2:
Assert.assertArrayEquals(CONFIG_ARRAY_2.toArray(),
cfg.getConfigArray().toArray());
break;
case VehiclePropertyIds.HVAC_TEMPERATURE_SET:
break;
default:
Assert.fail("Unexpected CarPropertyConfig: " + cfg.toString());
}
}
}
@Test
public void testGetMixTypeProperty() {
mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_1,
0, EXPECTED_VALUE_1);
CarPropertyValue<Object[]> result = mManager.getProperty(
CUSTOM_GLOBAL_MIXED_PROP_ID_1, 0);
Assert.assertArrayEquals(EXPECTED_VALUE_1, result.getValue());
mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_2,
0, EXPECTED_VALUE_2);
result = mManager.getProperty(
CUSTOM_GLOBAL_MIXED_PROP_ID_2, 0);
Assert.assertArrayEquals(EXPECTED_VALUE_2, result.getValue());
}
@Test
public void testGetPropertyConfig() {
CarPropertyConfig config = mManager.getCarPropertyConfig(CUSTOM_GLOBAL_MIXED_PROP_ID_1);
Assert.assertEquals(CUSTOM_GLOBAL_MIXED_PROP_ID_1, config.getPropertyId());
// return null if can not find the propertyConfig for the property.
Assert.assertNull(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID));
}
@Test
public void testGetAreaId() {
int result = mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_1_LEFT);
Assert.assertEquals(DRIVER_SIDE_AREA_ID, result);
//test for the GLOBAL property
int globalAreaId =
mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_2, VehicleAreaSeat.ROW_1_LEFT);
Assert.assertEquals(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, globalAreaId);
//test exception
try {
int areaId = mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_1,
VehicleAreaSeat.ROW_3_CENTER);
Assert.fail("Unexpected areaId: " + areaId);
} catch (IllegalArgumentException e) {
Log.v(TAG, e.getMessage());
}
try {
// test exception
int areaIdForFakeProp = mManager.getAreaId(FAKE_PROPERTY_ID,
VehicleAreaSeat.ROW_1_LEFT);
Assert.fail("Unexpected areaId for fake property: " + areaIdForFakeProp);
} catch (IllegalArgumentException e) {
Log.v(TAG, e.getMessage());
}
}
@Test
public void testNotReceiveOnErrorEvent() {
TestCallback callback = new TestCallback();
mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
CarPropertyManager.SENSOR_RATE_ONCHANGE);
injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
// app never change the value of HVAC_TEMPERATURE_SET, it won't get an error code.
SystemClock.sleep(SHORT_WAIT_TIMEOUT_MS);
Assert.assertFalse(callback.mReceivedErrorEventWithErrorCode);
Assert.assertFalse(callback.mReceivedErrorEventWithOutErrorCode);
}
@Test
public void testReceiveOnErrorEvent() {
TestCallback callback = new TestCallback();
mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
CarPropertyManager.SENSOR_RATE_ONCHANGE);
mManager.setFloatProperty(
VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
CHANGED_TEMP_VALUE);
injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
SystemClock.sleep(SHORT_WAIT_TIMEOUT_MS);
Assert.assertTrue(callback.mReceivedErrorEventWithErrorCode);
Assert.assertEquals(CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN,
callback.mErrorCode);
Assert.assertFalse(callback.mReceivedErrorEventWithOutErrorCode);
}
@Test
public void testNotReceiveOnErrorEventAfterUnregister() {
TestCallback callback1 = new TestCallback();
TestCallback callback2 = new TestCallback();
mManager.registerCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
CarPropertyManager.SENSOR_RATE_ONCHANGE);
mManager.registerCallback(callback2, VehiclePropertyIds.HVAC_TEMPERATURE_SET,
CarPropertyManager.SENSOR_RATE_ONCHANGE);
mManager.setFloatProperty(
VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
CHANGED_TEMP_VALUE);
mManager.unregisterCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET);
injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID,
CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
SystemClock.sleep(SHORT_WAIT_TIMEOUT_MS);
Assert.assertFalse(callback1.mReceivedErrorEventWithErrorCode);
Assert.assertFalse(callback1.mReceivedErrorEventWithOutErrorCode);
}
@Override
protected synchronized void configureMockedHal() {
PropertyHandler handler = new PropertyHandler();
addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1)
.addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID);
addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_2, handler).setConfigArray(CONFIG_ARRAY_2);
VehiclePropValue tempValue = new VehiclePropValue();
tempValue.value.floatValues.add(INIT_TEMP_VALUE);
tempValue.prop = VehiclePropertyIds.HVAC_TEMPERATURE_SET;
addProperty(VehiclePropertyIds.HVAC_TEMPERATURE_SET, tempValue)
.addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID);
}
private class PropertyHandler implements VehicleHalPropertyHandler {
HashMap<Integer, VehiclePropValue> mMap = new HashMap<>();
@Override
public synchronized void onPropertySet(VehiclePropValue value) {
mMap.put(value.prop, value);
}
@Override
public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
VehiclePropValue currentValue = mMap.get(value.prop);
return currentValue != null ? currentValue : value;
}
@Override
public synchronized void onPropertySubscribe(int property, float sampleRate) {
Log.d(TAG, "onPropertySubscribe property "
+ property + " sampleRate " + sampleRate);
}
@Override
public synchronized void onPropertyUnsubscribe(int property) {
Log.d(TAG, "onPropertyUnSubscribe property " + property);
}
}
private static class TestCallback implements CarPropertyManager.CarPropertyEventCallback {
private static final String CALLBACK_TAG = "ErrorEventTest";
private boolean mReceivedErrorEventWithErrorCode = false;
private boolean mReceivedErrorEventWithOutErrorCode = false;
private int mErrorCode;
@Override
public void onChangeEvent(CarPropertyValue value) {
Log.d(CALLBACK_TAG, "onChangeEvent: " + value);
}
@Override
public void onErrorEvent(int propId, int zone) {
mReceivedErrorEventWithOutErrorCode = true;
Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " zone: " + zone);
}
@Override
public void onErrorEvent(int propId, int areaId, int errorCode) {
mReceivedErrorEventWithErrorCode = true;
mErrorCode = errorCode;
Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " areaId: " + areaId
+ "errorCode: " + errorCode);
}
}
}