/*
* Copyright (C) 2024 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 android.car.hardware.property;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.FUEL_DOOR_OPEN;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import static android.car.VehiclePropertyIds.INFO_EV_CONNECTOR_TYPE;
import static android.car.VehiclePropertyIds.INFO_FUEL_DOOR_LOCATION;
import static android.car.VehiclePropertyIds.INITIAL_USER_INFO;
import static android.car.VehiclePropertyIds.INVALID;
import static android.car.hardware.property.CarPropertyManager.GetPropertyResult;
import static android.car.hardware.property.CarPropertyManager.PropertyAsyncError;
import static android.car.hardware.property.CarPropertyManager.SENSOR_RATE_ONCHANGE;
import static android.car.hardware.property.CarPropertyManager.SetPropertyRequest;
import static android.car.hardware.property.CarPropertyManager.SetPropertyResult;
import static com.android.car.internal.property.CarPropertyHelper.SYNC_OP_LIMIT_TRY_AGAIN;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.car.VehicleAreaSeat;
import android.car.VehicleAreaType;
import android.car.VehiclePropertyIds;
import android.car.feature.FeatureFlags;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArraySet;
import android.util.SparseArray;
import com.android.car.internal.ICarBase;
import com.android.car.internal.property.AsyncPropertyServiceRequest;
import com.android.car.internal.property.AsyncPropertyServiceRequestList;
import com.android.car.internal.property.CarPropertyConfigList;
import com.android.car.internal.property.CarPropertyErrorCodes;
import com.android.car.internal.property.CarSubscription;
import com.android.car.internal.property.GetPropertyConfigListResult;
import com.android.car.internal.property.GetSetValueResult;
import com.android.car.internal.property.GetSetValueResultList;
import com.android.car.internal.property.IAsyncPropertyResultCallback;
import com.android.car.internal.util.IntArray;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
/**
*
This class contains unit tests for the {@link CarPropertyManager}.
*/
@RunWith(MockitoJUnitRunner.class)
public final class CarPropertyManagerUnitTest {
// Required to set the process ID and set the "main" thread for this test, otherwise
// getMainLooper will return null.
@Rule
public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
.setProcessApp()
.setProvideMainThread(true)
.build();
// Defined as vendor property.
private static final int VENDOR_CONTINUOUS_PROPERTY = 0x21100111;
private static final int VENDOR_ON_CHANGE_PROPERTY = 0x21100222;
private static final int VENDOR_STATIC_PROPERTY = 0x21100333;
private static final int BOOLEAN_PROP = FUEL_DOOR_OPEN;
private static final int INT32_PROP = INFO_FUEL_DOOR_LOCATION;
private static final int INT32_VEC_PROP = INFO_EV_CONNECTOR_TYPE;
private static final int FLOAT_PROP = HVAC_TEMPERATURE_SET;
private static final float MIN_UPDATE_RATE_HZ = 10;
private static final float MAX_UPDATE_RATE_HZ = 100;
private static final float FIRST_UPDATE_RATE_HZ = 50;
private static final float LARGER_UPDATE_RATE_HZ = 50.1f;
private static final float SMALLER_UPDATE_RATE_HZ = 49.9f;
private static final int VENDOR_ERROR_CODE = 0x2;
private static final int VENDOR_ERROR_CODE_SHIFT = 16;
private static final int UNKNOWN_ERROR = -101;
private static final long TEST_TIMESTAMP = 1234;
private Handler mMainHandler;
private CarPropertyConfig mContinuousCarPropertyConfig;
private CarPropertyConfig mOnChangeCarPropertyConfig;
private CarPropertyConfig mStaticCarPropertyConfig;
private final SparseArray mCarPropertyConfigsById = new SparseArray<>();
private final ArraySet mUnsupportedPropIds = new ArraySet<>();
private final ArraySet mMissingPermissionPropIds = new ArraySet<>();
@Mock
private ICarBase mCar;
@Mock
private ApplicationInfo mApplicationInfo;
@Mock
private ICarProperty mICarProperty;
@Mock
private Context mContext;
@Mock
private CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback;
@Mock
private CarPropertyManager.CarPropertyEventCallback mCarPropertyEventCallback2;
@Mock
private CarPropertyManager.GetPropertyCallback mGetPropertyCallback;
@Mock
private CarPropertyManager.SetPropertyCallback mSetPropertyCallback;
@Mock
private Executor mMockExecutor1;
@Mock
private Executor mMockExecutor2;
@Mock
private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor mPropertyIdCaptor;
@Captor
private ArgumentCaptor mCarSubscriptionCaptor;
@Captor
private ArgumentCaptor mAsyncPropertyServiceRequestCaptor;
@Captor
private ArgumentCaptor mPropertyAsyncErrorCaptor;
@Captor
private ArgumentCaptor> mGetPropertyResultCaptor;
@Captor
private ArgumentCaptor mSetPropertyResultCaptor;
private CarPropertyManager mCarPropertyManager;
private static int combineErrors(int systemError, int vendorError) {
return vendorError << VENDOR_ERROR_CODE_SHIFT | systemError;
}
private static List createErrorCarPropertyEventList() {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
CarPropertyValue.STATUS_AVAILABLE, 0, -1);
CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_ERROR, value,
CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
return List.of(carPropertyEvent);
}
private static List createCarPropertyEventList() {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
CarPropertyEvent carPropertyEvent = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
return List.of(carPropertyEvent);
}
private static CarSubscription createCarSubscriptionOption(int propertyId,
int[] areaId, float updateRateHz) {
return createCarSubscriptionOption(propertyId, areaId, updateRateHz,
/* enableVur= */ false);
}
private static CarSubscription createCarSubscriptionOption(int propertyId,
int[] areaId, float updateRateHz, boolean enableVur) {
CarSubscription options = new CarSubscription();
options.propertyId = propertyId;
options.areaIds = areaId;
options.updateRateHz = updateRateHz;
options.enableVariableUpdateRate = enableVur;
return options;
}
private void addCarPropertyConfig(CarPropertyConfig config) {
mCarPropertyConfigsById.put(config.getPropertyId(), config);
}
private void setPropIdWithoutPermission(int propId) {
mCarPropertyConfigsById.remove(propId);
mMissingPermissionPropIds.add(propId);
}
private void setPropIdWithoutConfig(int propId) {
mCarPropertyConfigsById.remove(propId);
mUnsupportedPropIds.add(propId);
}
@Before
public void setUp() throws RemoteException {
mMainHandler = new Handler(Looper.getMainLooper());
when(mCar.getContext()).thenReturn(mContext);
when(mCar.getEventHandler()).thenReturn(mMainHandler);
when(mCar.handleRemoteExceptionFromCarService(any(RemoteException.class), any()))
.thenAnswer((inv) -> {
return inv.getArgument(1);
});
mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
mContinuousCarPropertyConfig = CarPropertyConfig.newBuilder(Integer.class,
VENDOR_CONTINUOUS_PROPERTY, VEHICLE_AREA_TYPE_GLOBAL)
.setChangeMode(CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS)
.setMinSampleRate(MIN_UPDATE_RATE_HZ)
.setMaxSampleRate(MAX_UPDATE_RATE_HZ)
.addAreaIdConfig(new AreaIdConfig.Builder(0)
.setSupportVariableUpdateRate(true).build())
.build();
mOnChangeCarPropertyConfig = CarPropertyConfig.newBuilder(Integer.class,
VENDOR_ON_CHANGE_PROPERTY, VEHICLE_AREA_TYPE_GLOBAL)
.setChangeMode(CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build())
.build();
mStaticCarPropertyConfig = CarPropertyConfig.newBuilder(Integer.class,
VENDOR_STATIC_PROPERTY, VEHICLE_AREA_TYPE_GLOBAL)
.setChangeMode(CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build())
.build();
when(mICarProperty.getPropertyConfigList(any())).thenAnswer((invocation) -> {
Object[] args = invocation.getArguments();
int[] propIds = (int[]) args[0];
GetPropertyConfigListResult result = new GetPropertyConfigListResult();
IntArray unsupportedPropIds = new IntArray();
IntArray missingPermissionPropIds = new IntArray();
List configs = new ArrayList<>();
for (int propId : propIds) {
if (mUnsupportedPropIds.contains(propId)) {
unsupportedPropIds.add(propId);
continue;
}
if (mMissingPermissionPropIds.contains(propId)) {
missingPermissionPropIds.add(propId);
continue;
}
var config = mCarPropertyConfigsById.get(propId);
if (config == null) {
unsupportedPropIds.add(propId);
continue;
}
configs.add(config);
}
result.carPropertyConfigList = new CarPropertyConfigList(configs);
result.unsupportedPropIds = unsupportedPropIds.toArray();
result.missingPermissionPropIds = missingPermissionPropIds.toArray();
return result;
});
addCarPropertyConfig(mContinuousCarPropertyConfig);
addCarPropertyConfig(mOnChangeCarPropertyConfig);
addCarPropertyConfig(mStaticCarPropertyConfig);
when(mICarProperty.getSupportedNoReadPermPropIds(any())).thenReturn(new int[0]);
mCarPropertyManager = new CarPropertyManager(mCar, mICarProperty);
// Enable the features.
when(mFeatureFlags.variableUpdateRate()).thenReturn(true);
mCarPropertyManager.setFeatureFlags(mFeatureFlags);
}
@Test
public void testGetProperty_returnsValue() throws RemoteException {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0)).isEqualTo(value);
}
@Test
public void testGetProperty_unsupportedProperty_exceptionAtU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getProperty(INVALID, 0));
}
@Test
public void testGetProperty_unsupportedProperty_nullBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThat(mCarPropertyManager.getProperty(INVALID, 0)).isNull();
}
@Test
public void testGetProperty_unsupportedPropertyInSvc_exceptionAtU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new IllegalArgumentException());
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_unsupportedPropertyInSvc_nullBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new IllegalArgumentException());
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0)).isNull();
}
@Test
public void testGetProperty_syncOpTryAgain() throws RemoteException {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(SYNC_OP_LIMIT_TRY_AGAIN)).thenReturn(value);
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0)).isEqualTo(value);
verify(mICarProperty, times(2)).getProperty(HVAC_TEMPERATURE_SET, 0);
}
@Test
public void testGetProperty_syncOpTryAgain_exceedRetryCountLimit() throws RemoteException {
// Car service will throw CarInternalException with version >= R.
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(SYNC_OP_LIMIT_TRY_AGAIN));
assertThrows(CarInternalErrorException.class, () ->
mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
verify(mICarProperty, times(10)).getProperty(HVAC_TEMPERATURE_SET, 0);
}
private void setAppTargetSdk(int appTargetSdk) {
mApplicationInfo.targetSdkVersion = appTargetSdk;
mCarPropertyManager = new CarPropertyManager(mCar, mICarProperty);
}
@Test
public void testGetProperty_notAvailableBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_notAvailableEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE));
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_tryAgainBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0)).isNull();
}
@Test
public void testGetProperty_tryAgainEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_accessDeniedBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_ACCESS_DENIED));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_accessDeniedEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_ACCESS_DENIED));
assertThrows(PropertyAccessDeniedSecurityException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_internalErrorBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_INTERNAL_ERROR));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_internalErrorEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_INTERNAL_ERROR));
assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_internalErrorEqualAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_INTERNAL_ERROR, VENDOR_ERROR_CODE)));
CarInternalErrorException exception = assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testGetProperty_unknownErrorBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(UNKNOWN_ERROR));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_unknownErrorEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(UNKNOWN_ERROR));
assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_returnsValueWithUnavailableStatusBeforeU() throws RemoteException {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
CarPropertyValue.STATUS_UNAVAILABLE, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, /*areaId=*/ 0)).isEqualTo(
new CarPropertyValue<>(HVAC_TEMPERATURE_SET, /*areaId=*/0,
CarPropertyValue.STATUS_UNAVAILABLE, TEST_TIMESTAMP, 17.0f));
}
@Test
public void testGetProperty_valueWithUnavailableStatusThrowsAfterU() throws RemoteException {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
CarPropertyValue.STATUS_UNAVAILABLE, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_returnsValueWithErrorStatusBeforeU() throws RemoteException {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
CarPropertyValue.STATUS_ERROR, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, /*areaId=*/ 0)).isEqualTo(
new CarPropertyValue<>(HVAC_TEMPERATURE_SET, /*areaId=*/0,
CarPropertyValue.STATUS_ERROR, TEST_TIMESTAMP, 17.0f));
}
@Test
public void testGetProperty_valueWithErrorStatusThrowsAfterU() throws RemoteException {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
CarPropertyValue.STATUS_ERROR, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_returnsValueWithUnknownStatusBeforeU() throws RemoteException {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
/*unknown status=*/999, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, /*areaId=*/ 0)).isEqualTo(
new CarPropertyValue<>(HVAC_TEMPERATURE_SET, /*areaId=*/0, /*status=*/999,
TEST_TIMESTAMP, 17.0f));
}
@Test
public void testGetProperty_valueWithUnknownStatusThrowsAfterU() throws RemoteException {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
/*unknown status=*/999, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetPropertyWithClass() throws Exception {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getProperty(Float.class, HVAC_TEMPERATURE_SET, 0).getValue())
.isEqualTo(17.0f);
}
@Test
public void testGetPropertyWithClass_mismatchClass() throws Exception {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getProperty(Integer.class, HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetPropertyWithClass_tryAgainBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.getProperty(Float.class, HVAC_TEMPERATURE_SET, 0))
.isNull();
}
@Test
public void testGetPropertyWithClass_tryAgainEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mCarPropertyManager.getProperty(Float.class, HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetBooleanProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
CarPropertyValue value = new CarPropertyValue<>(BOOLEAN_PROP, 0, true);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0)).isTrue();
}
@Test
public void testGetBooleanProperty_notAvailableBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_notAvailableEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE));
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetProperty_notAvailableEqualAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE, VENDOR_ERROR_CODE)));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testGetProperty_notAvailableDisabledBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED));
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_notAvailableDisabledAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_DISABLED);
}
@Test
public void testGetProperty_notAvailableDisabledAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED, VENDOR_ERROR_CODE)));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_DISABLED);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testGetProperty_notAvailableSafetyBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY));
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_notAvailableSafetyAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SAFETY);
}
@Test
public void testGetProperty_notAvailableSafetyAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY, VENDOR_ERROR_CODE)));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SAFETY);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testGetProperty_notAvailableSpeedHighBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH));
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_notAvailableSpeedHighAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_HIGH);
}
@Test
public void testGetProperty_notAvailableSpeedHighAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH, VENDOR_ERROR_CODE)));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_HIGH);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testGetProperty_notAvailableSpeedLowBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW));
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetProperty_notAvailableSpeedLowAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_LOW);
}
@Test
public void testGetProperty_notAvailableSpeedLowAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW, VENDOR_ERROR_CODE)));
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.getProperty(HVAC_TEMPERATURE_SET, 0));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_LOW);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testGetBooleanProperty_tryAgainBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0)).isFalse();
}
@Test
public void testGetBooleanProperty_tryAgainEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_accessDeniedBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_ACCESS_DENIED));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_accessDeniedEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_ACCESS_DENIED));
assertThrows(PropertyAccessDeniedSecurityException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_internalErrorBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_INTERNAL_ERROR));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_internalErrorEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_INTERNAL_ERROR));
assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_unknownErrorBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(UNKNOWN_ERROR));
assertThrows(IllegalStateException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetBooleanProperty_unknownErrorEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(BOOLEAN_PROP, 0)).thenThrow(
new ServiceSpecificException(UNKNOWN_ERROR));
assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.getBooleanProperty(BOOLEAN_PROP, 0));
}
@Test
public void testGetIntProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
CarPropertyValue value = new CarPropertyValue<>(INT32_PROP, 0, 1);
when(mICarProperty.getProperty(INT32_PROP, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getIntProperty(INT32_PROP, 0)).isEqualTo(1);
}
@Test
public void testGetIntProperty_tryAgainBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(INT32_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.getIntProperty(INT32_PROP, 0)).isEqualTo(0);
}
@Test
public void testGetIntProperty_tryAgainEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(INT32_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mCarPropertyManager.getIntProperty(INT32_PROP, 0));
}
@Test
public void testGetIntProperty_wrongType() throws Exception {
CarPropertyValue value = new CarPropertyValue<>(INT32_PROP, 0, 1);
when(mICarProperty.getProperty(INT32_PROP, 0)).thenReturn(value);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getFloatProperty(INT32_PROP, 0));
}
@Test
public void testGetIntArrayProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
CarPropertyValue value = new CarPropertyValue<>(FLOAT_PROP, 0, 1f);
when(mICarProperty.getProperty(FLOAT_PROP, 0)).thenReturn(value);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getIntArrayProperty(FLOAT_PROP, 0));
}
@Test
public void testGetIntArrayProperty_tryAgainBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(INT32_VEC_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.getIntArrayProperty(INT32_VEC_PROP, 0)).isEqualTo(
new int[0]);
}
@Test
public void testGetIntArrayProperty_tryAgainEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(INT32_VEC_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mCarPropertyManager.getIntArrayProperty(INT32_VEC_PROP, 0));
}
@Test
public void testGetFloatProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
CarPropertyValue value = new CarPropertyValue<>(FLOAT_PROP, 0, 1.f);
when(mICarProperty.getProperty(FLOAT_PROP, 0)).thenReturn(value);
assertThat(mCarPropertyManager.getFloatProperty(FLOAT_PROP, 0)).isEqualTo(1.f);
}
@Test
public void testGetFloatProperty_tryAgainBeforeR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.Q);
when(mICarProperty.getProperty(FLOAT_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.getFloatProperty(FLOAT_PROP, 0)).isEqualTo(0.f);
}
@Test
public void testGetFloatProperty_tryAgainEqualAfterR() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.R);
when(mICarProperty.getProperty(FLOAT_PROP, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mCarPropertyManager.getFloatProperty(FLOAT_PROP, 0));
}
@Test
public void testGetFloatProperty_wrongType() throws Exception {
CarPropertyValue value = new CarPropertyValue<>(INT32_PROP, 0, 1);
when(mICarProperty.getProperty(INT32_PROP, 0)).thenReturn(value);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getFloatProperty(INT32_PROP, 0));
}
private CarPropertyManager.GetPropertyRequest createGetPropertyRequest() {
return mCarPropertyManager.generateGetPropertyRequest(HVAC_TEMPERATURE_SET, 0);
}
@Test
public void testGetPropertiesAsync() throws RemoteException {
mCarPropertyManager.getPropertiesAsync(List.of(createGetPropertyRequest()), null, null,
mGetPropertyCallback);
ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(
AsyncPropertyServiceRequestList.class);
verify(mICarProperty).getPropertiesAsync(argumentCaptor.capture(), any(), anyLong());
assertThat(argumentCaptor.getValue().getList().get(0).getRequestId()).isEqualTo(0);
assertThat(argumentCaptor.getValue().getList().get(0).getPropertyId())
.isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(argumentCaptor.getValue().getList().get(0).getAreaId()).isEqualTo(0);
}
@Test
public void testGetPropertiesAsyncWithTimeout() throws RemoteException {
mCarPropertyManager.getPropertiesAsync(List.of(createGetPropertyRequest()),
/* timeoutInMs= */ 1000, null, null, mGetPropertyCallback);
ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(
AsyncPropertyServiceRequestList.class);
verify(mICarProperty).getPropertiesAsync(argumentCaptor.capture(), any(), eq(1000L));
assertThat(argumentCaptor.getValue().getList().get(0).getRequestId()).isEqualTo(0);
assertThat(argumentCaptor.getValue().getList().get(0).getPropertyId())
.isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(argumentCaptor.getValue().getList().get(0).getAreaId()).isEqualTo(0);
}
@Test
public void testGetPropertiesAsync_illegalArgumentException() throws RemoteException {
IllegalArgumentException exception = new IllegalArgumentException();
doThrow(exception).when(mICarProperty).getPropertiesAsync(any(
AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getPropertiesAsync(
List.of(createGetPropertyRequest()), null, null, mGetPropertyCallback));
}
@Test
public void testGetPropertiesAsync_SecurityException() throws RemoteException {
SecurityException exception = new SecurityException();
doThrow(exception).when(mICarProperty).getPropertiesAsync(any(
AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
assertThrows(SecurityException.class,
() -> mCarPropertyManager.getPropertiesAsync(
List.of(createGetPropertyRequest()), null, null, mGetPropertyCallback));
}
@Test
public void tsetGetPropertiesAsync_unsupportedProperty() throws Exception {
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getPropertiesAsync(
List.of(mCarPropertyManager.generateGetPropertyRequest(INVALID, 0)), null,
null, mGetPropertyCallback));
}
@Test
public void testGetPropertiesAsync_remoteException() throws RemoteException {
RemoteException remoteException = new RemoteException();
doThrow(remoteException).when(mICarProperty).getPropertiesAsync(any(
AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
mCarPropertyManager.getPropertiesAsync(List.of(createGetPropertyRequest()), null, null,
mGetPropertyCallback);
verify(mCar).handleRemoteExceptionFromCarService(any(RemoteException.class));
}
@Test
public void testGetPropertiesAsync_clearRequestIdAfterFailed() throws RemoteException {
CarPropertyManager.GetPropertyRequest getPropertyRequest = createGetPropertyRequest();
IllegalArgumentException exception = new IllegalArgumentException();
doThrow(exception).when(mICarProperty).getPropertiesAsync(any(
AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getPropertiesAsync(List.of(getPropertyRequest), null,
null, mGetPropertyCallback));
clearInvocations(mICarProperty);
doNothing().when(mICarProperty).getPropertiesAsync(any(
AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(
AsyncPropertyServiceRequestList.class);
mCarPropertyManager.getPropertiesAsync(List.of(getPropertyRequest), null, null,
mGetPropertyCallback);
verify(mICarProperty).getPropertiesAsync(argumentCaptor.capture(), any(), anyLong());
assertThat(argumentCaptor.getValue().getList().get(0).getRequestId()).isEqualTo(0);
assertThat(argumentCaptor.getValue().getList().get(0).getPropertyId())
.isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(argumentCaptor.getValue().getList().get(0).getAreaId()).isEqualTo(0);
}
@Test
@IgnoreUnderRavenwood(blockedBy = android.os.CancellationSignal.class)
public void testGetPropertiesAsync_cancellationSignalCancelRequests() throws Exception {
CarPropertyManager.GetPropertyRequest getPropertyRequest = createGetPropertyRequest();
CancellationSignal cancellationSignal = new CancellationSignal();
List callbackWrapper = new ArrayList<>();
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
callbackWrapper.add((IAsyncPropertyResultCallback) args[1]);
return null;
}).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
mCarPropertyManager.getPropertiesAsync(List.of(getPropertyRequest), cancellationSignal,
/* callbackExecutor= */ null, mGetPropertyCallback);
// Cancel the pending request.
cancellationSignal.cancel();
verify(mICarProperty).cancelRequests(new int[]{0});
// Call the manager callback after the request is already cancelled.
GetSetValueResult getValueResult = GetSetValueResult.newErrorResult(
0,
new CarPropertyErrorCodes(
CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR,
/* vendorErrorCode= */ 0,
/* systemErrorCode= */ 0));
assertThat(callbackWrapper.size()).isEqualTo(1);
callbackWrapper.get(0).onGetValueResults(
new GetSetValueResultList(List.of(getValueResult)));
// No client callbacks should be called.
verify(mGetPropertyCallback, never()).onFailure(any());
verify(mGetPropertyCallback, never()).onSuccess(any());
}
@Test
public void testOnGetValueResult_onSuccess() throws RemoteException {
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
AsyncPropertyServiceRequestList asyncGetPropertyServiceRequestList =
(AsyncPropertyServiceRequestList) args[0];
List getPropertyServiceList = asyncGetPropertyServiceRequestList.getList();
AsyncPropertyServiceRequest getPropertyServiceRequest =
(AsyncPropertyServiceRequest) getPropertyServiceList.get(0);
IAsyncPropertyResultCallback getAsyncPropertyResultCallback =
(IAsyncPropertyResultCallback) args[1];
assertThat(getPropertyServiceRequest.getRequestId()).isEqualTo(0);
assertThat(getPropertyServiceRequest.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
GetSetValueResult getValueResult = GetSetValueResult.newGetValueResult(0, value);
getAsyncPropertyResultCallback.onGetValueResults(
new GetSetValueResultList(List.of(getValueResult)));
return null;
}).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
mCarPropertyManager.getPropertiesAsync(List.of(createGetPropertyRequest()), null, null,
mGetPropertyCallback);
verify(mGetPropertyCallback, timeout(1000)).onSuccess(
mGetPropertyResultCaptor.capture());
GetPropertyResult gotResult = (GetPropertyResult)
mGetPropertyResultCaptor.getValue();
assertThat(gotResult.getRequestId()).isEqualTo(0);
assertThat(gotResult.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(gotResult.getAreaId()).isEqualTo(0);
assertThat(gotResult.getValue()).isEqualTo(17.0f);
}
@Test
public void testOnGetValueResult_onSuccessMultipleRequests() throws RemoteException {
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
AsyncPropertyServiceRequestList getPropertyServiceRequest =
(AsyncPropertyServiceRequestList) args[0];
List getPropertyServiceRequests =
getPropertyServiceRequest.getList();
IAsyncPropertyResultCallback getAsyncPropertyResultCallback =
(IAsyncPropertyResultCallback) args[1];
assertThat(getPropertyServiceRequests.size()).isEqualTo(2);
assertThat(getPropertyServiceRequests.get(0).getRequestId()).isEqualTo(0);
assertThat(getPropertyServiceRequests.get(0).getPropertyId()).isEqualTo(
HVAC_TEMPERATURE_SET);
assertThat(getPropertyServiceRequests.get(1).getRequestId()).isEqualTo(1);
assertThat(getPropertyServiceRequests.get(1).getPropertyId()).isEqualTo(
HVAC_TEMPERATURE_SET);
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0, 17.0f);
List getValueResults = List.of(
GetSetValueResult.newGetValueResult(0, value),
GetSetValueResult.newGetValueResult(1, value));
getAsyncPropertyResultCallback.onGetValueResults(
new GetSetValueResultList(getValueResults));
return null;
}).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
List getPropertyRequests = new ArrayList<>();
getPropertyRequests.add(createGetPropertyRequest());
getPropertyRequests.add(createGetPropertyRequest());
mCarPropertyManager.getPropertiesAsync(getPropertyRequests, null, null,
mGetPropertyCallback);
verify(mGetPropertyCallback, timeout(1000).times(2)).onSuccess(
mGetPropertyResultCaptor.capture());
List> gotPropertyResults = mGetPropertyResultCaptor.getAllValues();
assertThat(gotPropertyResults.get(0).getRequestId()).isEqualTo(0);
assertThat(gotPropertyResults.get(0).getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(gotPropertyResults.get(0).getAreaId()).isEqualTo(0);
assertThat(gotPropertyResults.get(0).getValue()).isEqualTo(17.0f);
assertThat(gotPropertyResults.get(1).getRequestId()).isEqualTo(1);
assertThat(gotPropertyResults.get(1).getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(gotPropertyResults.get(1).getAreaId()).isEqualTo(0);
assertThat(gotPropertyResults.get(1).getValue()).isEqualTo(17.0f);
}
@Test
public void testOnGetValueResult_onFailure() throws RemoteException {
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
AsyncPropertyServiceRequestList asyncPropertyServiceREquestList =
(AsyncPropertyServiceRequestList) args[0];
List getPropertyServiceList = asyncPropertyServiceREquestList.getList();
AsyncPropertyServiceRequest getPropertyServiceRequest =
(AsyncPropertyServiceRequest) getPropertyServiceList.get(0);
IAsyncPropertyResultCallback getAsyncPropertyResultCallback =
(IAsyncPropertyResultCallback) args[1];
assertThat(getPropertyServiceRequest.getRequestId()).isEqualTo(0);
assertThat(getPropertyServiceRequest.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
GetSetValueResult getValueResult = GetSetValueResult.newErrorResult(
0,
new CarPropertyErrorCodes(
CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR, VENDOR_ERROR_CODE, 0));
getAsyncPropertyResultCallback.onGetValueResults(
new GetSetValueResultList(List.of(getValueResult)));
return null;
}).when(mICarProperty).getPropertiesAsync(any(), any(), anyLong());
mCarPropertyManager.getPropertiesAsync(List.of(createGetPropertyRequest()), null, null,
mGetPropertyCallback);
verify(mGetPropertyCallback, timeout(1000)).onFailure(mPropertyAsyncErrorCaptor.capture());
PropertyAsyncError error = mPropertyAsyncErrorCaptor.getValue();
assertThat(error.getRequestId()).isEqualTo(0);
assertThat(error.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(error.getAreaId()).isEqualTo(0);
assertThat(error.getErrorCode()).isEqualTo(
CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
assertThat(error.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testSetProperty_setsValue() throws RemoteException {
mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f);
ArgumentCaptor value = ArgumentCaptor.forClass(CarPropertyValue.class);
verify(mICarProperty).setProperty(value.capture(), any());
assertThat(value.getValue().getValue()).isEqualTo(17.0f);
}
@Test
public void testSetProperty_syncOpTryAgain() throws RemoteException {
doThrow(new ServiceSpecificException(SYNC_OP_LIMIT_TRY_AGAIN)).doNothing()
.when(mICarProperty).setProperty(any(), any());
mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f);
verify(mICarProperty, times(2)).setProperty(any(), any());
}
@Test
public void testSetProperty_unsupportedProperty() throws RemoteException {
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.setProperty(Float.class, INVALID, 0, 17.0f));
}
private SetPropertyRequest createSetPropertyRequest() {
return mCarPropertyManager.generateSetPropertyRequest(HVAC_TEMPERATURE_SET, 0,
Float.valueOf(17.0f));
}
@Test
public void testSetPropertiesAsync() throws RemoteException {
SetPropertyRequest setPropertyRequest = createSetPropertyRequest();
setPropertyRequest.setUpdateRateHz(10.1f);
setPropertyRequest.setWaitForPropertyUpdate(false);
mCarPropertyManager.setPropertiesAsync(List.of(setPropertyRequest), null, null,
mSetPropertyCallback);
verify(mICarProperty).setPropertiesAsync(mAsyncPropertyServiceRequestCaptor.capture(),
any(), anyLong());
AsyncPropertyServiceRequest request = mAsyncPropertyServiceRequestCaptor.getValue()
.getList().get(0);
assertThat(request.getRequestId()).isEqualTo(0);
assertThat(request.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(request.getAreaId()).isEqualTo(0);
assertThat(request.isWaitForPropertyUpdate()).isFalse();
assertThat(request.getUpdateRateHz()).isEqualTo(10.1f);
CarPropertyValue requestValue = request.getCarPropertyValue();
assertThat(requestValue).isNotNull();
assertThat(requestValue.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(requestValue.getAreaId()).isEqualTo(0);
assertThat(requestValue.getValue()).isEqualTo(17.0f);
}
@Test
public void testSetPropertiesAsync_nullRequests() throws RemoteException {
assertThrows(NullPointerException.class,
() -> mCarPropertyManager.setPropertiesAsync(
null, null, null, mSetPropertyCallback));
}
@Test
public void testSetPropertiesAsync_nullCallback() throws RemoteException {
assertThrows(NullPointerException.class,
() -> mCarPropertyManager.setPropertiesAsync(
List.of(createSetPropertyRequest()), null, null, null));
}
@Test
public void testSetPropertiesAsyncWithTimeout() throws RemoteException {
mCarPropertyManager.setPropertiesAsync(List.of(createSetPropertyRequest()),
/* timeoutInMs= */ 1000, /* cancellationSignal= */ null,
/* callbackExecutor= */ null, mSetPropertyCallback);
verify(mICarProperty).setPropertiesAsync(mAsyncPropertyServiceRequestCaptor.capture(),
any(), eq(1000L));
AsyncPropertyServiceRequest request = mAsyncPropertyServiceRequestCaptor.getValue()
.getList().get(0);
assertThat(request.getRequestId()).isEqualTo(0);
assertThat(request.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(request.getAreaId()).isEqualTo(0);
CarPropertyValue requestValue = request.getCarPropertyValue();
assertThat(requestValue).isNotNull();
assertThat(requestValue.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(requestValue.getAreaId()).isEqualTo(0);
assertThat(requestValue.getValue()).isEqualTo(17.0f);
}
@Test
public void testSetPropertiesAsync_illegalArgumentException() throws RemoteException {
doThrow(new IllegalArgumentException()).when(mICarProperty).setPropertiesAsync(
any(AsyncPropertyServiceRequestList.class), any(IAsyncPropertyResultCallback.class),
anyLong());
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.setPropertiesAsync(
List.of(createSetPropertyRequest()), null, null, mSetPropertyCallback));
}
@Test
public void testSetPropertiesAsync_SecurityException() throws RemoteException {
doThrow(new SecurityException()).when(mICarProperty).setPropertiesAsync(
any(AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
assertThrows(SecurityException.class,
() -> mCarPropertyManager.setPropertiesAsync(
List.of(createSetPropertyRequest()), null, null, mSetPropertyCallback));
}
@Test
public void testSetPropertiesAsync_unsupportedProperty() throws Exception {
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.setPropertiesAsync(
List.of(mCarPropertyManager.generateSetPropertyRequest(
INVALID, 0, Integer.valueOf(0))),
null, null, mSetPropertyCallback));
}
@Test
public void testSetPropertiesAsync_remoteException() throws RemoteException {
doThrow(new RemoteException()).when(mICarProperty).setPropertiesAsync(
any(AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
mCarPropertyManager.setPropertiesAsync(List.of(createSetPropertyRequest()), null, null,
mSetPropertyCallback);
verify(mCar).handleRemoteExceptionFromCarService(any(RemoteException.class));
}
@Test
public void testSetPropertiesAsync_duplicateRequestId() throws RemoteException {
SetPropertyRequest request = createSetPropertyRequest();
mCarPropertyManager.setPropertiesAsync(List.of(request), null, null,
mSetPropertyCallback);
// Send the same request again with the same request ID is not allowed.
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.setPropertiesAsync(List.of(request), null, null,
mSetPropertyCallback));
}
@Test
public void testSetPropertiesAsync_clearRequestIdAfterFailed() throws RemoteException {
SetPropertyRequest setPropertyRequest = createSetPropertyRequest();
IllegalArgumentException exception = new IllegalArgumentException();
doThrow(exception).when(mICarProperty).setPropertiesAsync(
any(AsyncPropertyServiceRequestList.class), any(IAsyncPropertyResultCallback.class),
anyLong());
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.setPropertiesAsync(List.of(setPropertyRequest), null,
null, mSetPropertyCallback));
clearInvocations(mICarProperty);
doNothing().when(mICarProperty).setPropertiesAsync(
any(AsyncPropertyServiceRequestList.class),
any(IAsyncPropertyResultCallback.class), anyLong());
// After the first request failed, the request ID map should be cleared so we can use the
// same request ID again.
mCarPropertyManager.setPropertiesAsync(List.of(setPropertyRequest), null, null,
mSetPropertyCallback);
verify(mICarProperty).setPropertiesAsync(any(), any(), anyLong());
}
@Test
public void testSetProperty_notAvailableAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE, VENDOR_ERROR_CODE))).when(mICarProperty)
.setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testSetProperty_internalErrorAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_INTERNAL_ERROR, VENDOR_ERROR_CODE))).when(mICarProperty)
.setProperty(eq(carPropertyValue), any());
CarInternalErrorException exception = assertThrows(CarInternalErrorException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testSetProperty_notAvailableDisabledBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
}
@Test
public void testSetProperty_notAvailableDisabledAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_DISABLED);
}
@Test
public void testSetProperty_notAvailableDisabledAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED, VENDOR_ERROR_CODE)))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_DISABLED);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testSetProperty_notAvailableSafetyBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
}
@Test
public void testSetProperty_notAvailableSafetyAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SAFETY);
}
@Test
public void testSetProperty_notAvailableSafetyAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY, VENDOR_ERROR_CODE)))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SAFETY);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testSetProperty_notAvailableSpeedHighBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
}
@Test
public void testSetProperty_notAvailableSpeedHighAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_HIGH);
}
@Test
public void testSetProperty_notAvailableSpeedHighAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH, VENDOR_ERROR_CODE)))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_HIGH);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testSetProperty_notAvailableSpeedLowBeforeU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
}
@Test
public void testSetProperty_notAvailableSpeedLowAfterU() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_LOW);
}
@Test
public void testSetProperty_notAvailableSpeedLowAfterU_withVendorErrorCode() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
CarPropertyValue carPropertyValue = new CarPropertyValue<>(
HVAC_TEMPERATURE_SET, 0, 17.0f);
doThrow(new ServiceSpecificException(combineErrors(
VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW, VENDOR_ERROR_CODE)))
.when(mICarProperty).setProperty(eq(carPropertyValue), any());
PropertyNotAvailableException exception = assertThrows(PropertyNotAvailableException.class,
() -> mCarPropertyManager.setProperty(Float.class, HVAC_TEMPERATURE_SET, 0, 17.0f));
assertThat(exception.getDetailedErrorCode())
.isEqualTo(PropertyNotAvailableErrorCode.NOT_AVAILABLE_SPEED_LOW);
assertThat(exception.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testOnSetValueResult_onSuccess() throws RemoteException {
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
AsyncPropertyServiceRequestList setPropertyRequest =
(AsyncPropertyServiceRequestList) args[0];
List setPropertyServiceList = setPropertyRequest.getList();
AsyncPropertyServiceRequest setPropertyServiceRequest =
(AsyncPropertyServiceRequest) setPropertyServiceList.get(0);
IAsyncPropertyResultCallback setAsyncPropertyResultCallback =
(IAsyncPropertyResultCallback) args[1];
assertThat(setPropertyServiceRequest.getRequestId()).isEqualTo(0);
assertThat(setPropertyServiceRequest.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(setPropertyServiceRequest.getCarPropertyValue().getValue()).isEqualTo(
17.0f);
GetSetValueResult setValueResult = GetSetValueResult.newSetValueResult(0,
/* updateTimestampNanos= */ TEST_TIMESTAMP);
setAsyncPropertyResultCallback.onSetValueResults(
new GetSetValueResultList(List.of(setValueResult)));
return null;
}).when(mICarProperty).setPropertiesAsync(any(), any(), anyLong());
mCarPropertyManager.setPropertiesAsync(List.of(createSetPropertyRequest()), null, null,
mSetPropertyCallback);
verify(mSetPropertyCallback, timeout(1000)).onSuccess(mSetPropertyResultCaptor.capture());
SetPropertyResult gotResult = mSetPropertyResultCaptor.getValue();
assertThat(gotResult.getRequestId()).isEqualTo(0);
assertThat(gotResult.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(gotResult.getAreaId()).isEqualTo(0);
assertThat(gotResult.getUpdateTimestampNanos()).isEqualTo(TEST_TIMESTAMP);
}
@Test
public void testOnSetValueResult_onSuccessMultipleRequests() throws RemoteException {
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
AsyncPropertyServiceRequestList setPropertyServiceRequest =
(AsyncPropertyServiceRequestList) args[0];
List setPropertyServiceRequests =
setPropertyServiceRequest.getList();
IAsyncPropertyResultCallback setAsyncPropertyResultCallback =
(IAsyncPropertyResultCallback) args[1];
assertThat(setPropertyServiceRequests.size()).isEqualTo(2);
assertThat(setPropertyServiceRequests.get(0).getRequestId()).isEqualTo(0);
assertThat(setPropertyServiceRequests.get(0).getPropertyId()).isEqualTo(
HVAC_TEMPERATURE_SET);
assertThat(setPropertyServiceRequests.get(1).getRequestId()).isEqualTo(1);
assertThat(setPropertyServiceRequests.get(1).getPropertyId()).isEqualTo(
HVAC_TEMPERATURE_SET);
List setValueResults = List.of(
GetSetValueResult.newSetValueResult(0,
/* updateTimestampNanos= */ TEST_TIMESTAMP),
GetSetValueResult.newSetValueResult(1,
/* updateTimestampNanos= */ TEST_TIMESTAMP));
setAsyncPropertyResultCallback.onSetValueResults(
new GetSetValueResultList(setValueResults));
return null;
}).when(mICarProperty).setPropertiesAsync(any(), any(), anyLong());
List> setPropertyRequests = new ArrayList<>();
setPropertyRequests.add(createSetPropertyRequest());
setPropertyRequests.add(createSetPropertyRequest());
mCarPropertyManager.setPropertiesAsync(setPropertyRequests, null, null,
mSetPropertyCallback);
verify(mSetPropertyCallback, timeout(1000).times(2)).onSuccess(
mSetPropertyResultCaptor.capture());
List gotPropertyResults = mSetPropertyResultCaptor.getAllValues();
assertThat(gotPropertyResults.get(0).getRequestId()).isEqualTo(0);
assertThat(gotPropertyResults.get(0).getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(gotPropertyResults.get(0).getAreaId()).isEqualTo(0);
assertThat(gotPropertyResults.get(0).getUpdateTimestampNanos()).isEqualTo(TEST_TIMESTAMP);
assertThat(gotPropertyResults.get(1).getRequestId()).isEqualTo(1);
assertThat(gotPropertyResults.get(1).getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(gotPropertyResults.get(1).getAreaId()).isEqualTo(0);
assertThat(gotPropertyResults.get(1).getUpdateTimestampNanos()).isEqualTo(TEST_TIMESTAMP);
}
@Test
public void testOnSetValueResult_onFailure() throws RemoteException {
doAnswer((invocation) -> {
Object[] args = invocation.getArguments();
AsyncPropertyServiceRequestList setPropertyService =
(AsyncPropertyServiceRequestList) args[0];
List setPropertyServiceList = setPropertyService.getList();
AsyncPropertyServiceRequest setPropertyServiceRequest =
(AsyncPropertyServiceRequest) setPropertyServiceList.get(0);
IAsyncPropertyResultCallback setAsyncPropertyResultCallback =
(IAsyncPropertyResultCallback) args[1];
assertThat(setPropertyServiceRequest.getRequestId()).isEqualTo(0);
assertThat(setPropertyServiceRequest.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
GetSetValueResult setValueResult = GetSetValueResult.newErrorSetValueResult(
0,
new CarPropertyErrorCodes(
CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR, VENDOR_ERROR_CODE, 0));
setAsyncPropertyResultCallback.onSetValueResults(
new GetSetValueResultList(List.of(setValueResult)));
return null;
}).when(mICarProperty).setPropertiesAsync(any(), any(), anyLong());
mCarPropertyManager.setPropertiesAsync(List.of(createSetPropertyRequest()), null, null,
mSetPropertyCallback);
verify(mSetPropertyCallback, timeout(1000)).onFailure(mPropertyAsyncErrorCaptor.capture());
PropertyAsyncError error = mPropertyAsyncErrorCaptor.getValue();
assertThat(error.getRequestId()).isEqualTo(0);
assertThat(error.getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(error.getAreaId()).isEqualTo(0);
assertThat(error.getErrorCode()).isEqualTo(
CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR);
assertThat(error.getVendorErrorCode()).isEqualTo(VENDOR_ERROR_CODE);
}
@Test
public void testRegisterCallback_returnsFalseIfPropertyIdNotSupportedInVehicle()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VehiclePropertyIds.INVALID, FIRST_UPDATE_RATE_HZ)).isFalse();
verify(mICarProperty, never()).registerListener(any(),
any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersWithServiceOnFirstCallback() throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
FIRST_UPDATE_RATE_HZ))), any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersWithMaxUpdateRateOnFirstCallback()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, MAX_UPDATE_RATE_HZ + 1)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
MAX_UPDATE_RATE_HZ))), any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersWithMinUpdateRateOnFirstCallback()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, MIN_UPDATE_RATE_HZ - 1)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
MIN_UPDATE_RATE_HZ))), any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersWithOnChangeRateForOnChangeProperty()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersWithOnChangeRateForStaticProperty()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_STATIC_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_STATIC_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_returnsFalseForRemoteException() throws RemoteException {
RemoteException remoteException = new RemoteException();
doThrow(remoteException).when(mICarProperty).registerListener(
eq(List.of(createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[] {0},
CarPropertyManager.SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
}
@Test
public void testRegisterCallback_recoversAfterFirstRemoteException() throws RemoteException {
RemoteException remoteException = new RemoteException();
doThrow(remoteException).doNothing().when(mICarProperty)
.registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[] {0},
SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
verify(mICarProperty, times(2)).registerListener(
eq(List.of(createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[] {0},
CarPropertyManager.SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_returnsFalseForIllegalArgumentException()
throws RemoteException {
doThrow(IllegalArgumentException.class).when(mICarProperty)
.registerListener(eq(List.of(createCarSubscriptionOption(
VENDOR_ON_CHANGE_PROPERTY, new int[] {0}, SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isFalse();
}
@Test
public void testRegisterCallback_registersTwiceWithHigherRateCallback() throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
VENDOR_CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty, times(2)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
LARGER_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
FIRST_UPDATE_RATE_HZ)));
}
@Test
public void testRegisterCallback_registersOnSecondHigherRateWithSameCallback()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
VENDOR_CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty, times(2)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
LARGER_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
FIRST_UPDATE_RATE_HZ)));
}
@Test
public void testRegisterCallback_registersOnSecondLowerRateWithSameCallback()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, SMALLER_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty, times(2)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
FIRST_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
SMALLER_UPDATE_RATE_HZ)));
}
@Test
public void testRegisterCallback_doesNotRegistersOnSecondLowerRateCallback()
throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
VENDOR_CONTINUOUS_PROPERTY, SMALLER_UPDATE_RATE_HZ)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
FIRST_UPDATE_RATE_HZ))),
any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersTwiceForDifferentProperties() throws RemoteException {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
verify(mICarProperty, times(2)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
FIRST_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[] {0},
CarPropertyManager.SENSOR_RATE_ONCHANGE)));
}
@Test
public void testRegisterCallback_registerInvalidProp() throws Exception {
assertThat(mCarPropertyManager.registerCallback(
mCarPropertyEventCallback, /* propertyId= */ -1, FIRST_UPDATE_RATE_HZ)).isFalse();
}
// We annotate the update rate to be within 0 and 100, however, in the actual implementation,
// we will fit update rate outside this range to the min and max update rate.
@Test
public void testRegisterCallback_updateRateOutsideFloatRangeMustNotThrow_tooLarge()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(
mCarPropertyEventCallback, VENDOR_CONTINUOUS_PROPERTY, /* updateRateHz= */ 101.f))
.isTrue();
verify(mICarProperty).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getValue()).isEqualTo(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
MAX_UPDATE_RATE_HZ)));
}
@Test
public void testRegisterCallback_updateRateOutsideFloatRangeMustNotThrow_tooSmall()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(
mCarPropertyEventCallback, VENDOR_CONTINUOUS_PROPERTY, /* updateRateHz= */ -1.f))
.isTrue();
verify(mICarProperty).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getValue()).isEqualTo(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
MIN_UPDATE_RATE_HZ)));
}
@Test
public void testRegisterCallback_isSupportedAndHasWritePermissionOnly() throws Exception {
int propId = VENDOR_CONTINUOUS_PROPERTY;
when(mICarProperty.isSupportedAndHasWritePermissionOnly(propId)).thenReturn(true);
assertThrows(SecurityException.class, () -> mCarPropertyManager.registerCallback(
mCarPropertyEventCallback, VENDOR_CONTINUOUS_PROPERTY, 0));
}
@Test
public void testRegisterCallback_isSupportedAndHasWritePermissionOnly_remoteException()
throws Exception {
int propId = VENDOR_CONTINUOUS_PROPERTY;
when(mICarProperty.isSupportedAndHasWritePermissionOnly(propId)).thenThrow(
new RemoteException());
assertThat(mCarPropertyManager.registerCallback(
mCarPropertyEventCallback, VENDOR_CONTINUOUS_PROPERTY, 0)).isFalse();
}
@Test
public void testSubscribePropertyEvents_registerMultipleEvents() throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
verify(mICarProperty).registerListener(
eq(List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_FAST, /* enableVur= */ true),
createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_sanitizeSampleRate() throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateHz(0.f).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback))
.isTrue();
verify(mICarProperty).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getValue()).isEqualTo(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[] {0},
MIN_UPDATE_RATE_HZ, /* enableVur= */ true)));
}
@Test
public void testSubscribePropertyEvents_registerMultipleEventsSameProperty_throws()
throws Exception {
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.addAreaId(0).setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.addAreaId(0).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback));
assertWithMessage("Overlapping areaIds").that(thrown).hasMessageThat()
.contains("Subscribe options contain overlapping propertyId");
}
@Test
public void testSubscribePropertyEvents_registerMultipleEvents_unsubscribe() throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0)
.build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
verify(mICarProperty).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_registerMultipleEventsWithSameProperty_unsubscribe()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFastest().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0)
.build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback2)).isTrue();
clearInvocations(mICarProperty);
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_FAST, /* enableVur= */ true))),
any(ICarPropertyEventListener.class));
verify(mICarProperty).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_withPropertyIdCallback() throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(
VENDOR_CONTINUOUS_PROPERTY, mCarPropertyEventCallback)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
MIN_UPDATE_RATE_HZ, /* enableVur= */ true))),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_withPropertyIdUpdateRateCallback() throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(
VENDOR_CONTINUOUS_PROPERTY, CarPropertyManager.SENSOR_RATE_FAST,
mCarPropertyEventCallback)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_FAST, /* enableVur= */ true))),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_withPropertyIdAreaIdCallback() throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(
VENDOR_CONTINUOUS_PROPERTY, /* areaId= */ 0,
mCarPropertyEventCallback)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
MIN_UPDATE_RATE_HZ, /* enableVur= */ true))),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_withPropertyIdAreaIdUpdateRateCallback()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(
VENDOR_CONTINUOUS_PROPERTY, /* areaId= */ 0,
CarPropertyManager.SENSOR_RATE_FAST,
mCarPropertyEventCallback)).isTrue();
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_FAST, /* enableVur= */ false))),
any(ICarPropertyEventListener.class));
}
@Test
public void testSubscribePropertyEvents_noReadPermission() throws Exception {
int propId = VENDOR_CONTINUOUS_PROPERTY;
when(mICarProperty.getSupportedNoReadPermPropIds(any()))
.thenReturn(new int[] {propId});
assertThrows(SecurityException.class, () -> mCarPropertyManager.subscribePropertyEvents(
propId, mCarPropertyEventCallback));
}
@Test
public void testSubscribePropertyEvents_getSupportedNoReadPermPropIds_remoteException()
throws Exception {
int propId = VENDOR_CONTINUOUS_PROPERTY;
when(mICarProperty.getSupportedNoReadPermPropIds(any()))
.thenThrow(new RemoteException());
assertThat(mCarPropertyManager.subscribePropertyEvents(
propId, mCarPropertyEventCallback)).isFalse();
}
@Test
public void testRegisterCallback_registersAgainWithDifferentExecutor_throws() throws Exception {
mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0)
.build()),
mMockExecutor1, mCarPropertyEventCallback);
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0)
.build()),
mMockExecutor2, mCarPropertyEventCallback));
assertWithMessage("Two executor subscription").that(thrown).hasMessageThat()
.contains("A different executor is already associated with this callback,"
+ " please use the same executor");
}
@Test
public void testRegisterCallback_registersAgainWithSameExecutor() throws Exception {
mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0)
.build()),
mMockExecutor1, mCarPropertyEventCallback);
mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY).addAreaId(0)
.setUpdateRateFast().build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).addAreaId(0)
.build()),
mMockExecutor1, mCarPropertyEventCallback);
verify(mICarProperty).registerListener(
eq(List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_FAST, /* enableVur= */ true),
createCarSubscriptionOption(VENDOR_ON_CHANGE_PROPERTY, new int[]{0},
CarPropertyManager.SENSOR_RATE_ONCHANGE))),
any(ICarPropertyEventListener.class));
}
@Test
public void testRegisterCallback_registersAgainIfTheFirstCallbackReturnsFalse()
throws RemoteException {
doThrow(IllegalArgumentException.class).doNothing().when(mICarProperty)
.registerListener(eq(List.of(
createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY,
new int[]{0}, FIRST_UPDATE_RATE_HZ))),
any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isFalse();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
}
@Test
public void testRegisterCallback_restoresOriginalRateHzIfTheSecondCallbackReturnsFalse()
throws RemoteException {
Float smallerUpdate = 1F;
Float largerUpdate = 2F;
doThrow(IllegalArgumentException.class).when(mICarProperty)
.registerListener(eq(List.of(createCarSubscriptionOption(
HVAC_TEMPERATURE_SET, new int[]{0}, largerUpdate))),
any(ICarPropertyEventListener.class));
CarPropertyValue goodValue = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
Duration.ofSeconds(1).toNanos(), 17.0f);
CarPropertyValue almostFreshValue = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
Duration.ofMillis(1899).toNanos(), 18.0f);
List eventList = List.of(
new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, goodValue),
new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
almostFreshValue)
);
CarPropertyConfig config = CarPropertyConfig.newBuilder(Float.class, HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build())
.setChangeMode(CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS)
.setMinSampleRate(0f)
.setMaxSampleRate(10f).build();
addCarPropertyConfig(config);
ICarPropertyEventListener listener = getCarPropertyEventListener();
ArgumentCaptor valueCaptor =
ArgumentCaptor.forClass(CarPropertyValue.class);
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
HVAC_TEMPERATURE_SET, smallerUpdate)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
HVAC_TEMPERATURE_SET, largerUpdate)).isFalse();
verify(mICarProperty, times(3)).registerListener(
any(), any(ICarPropertyEventListener.class));
listener.onEvent(eventList);
verify(mCarPropertyEventCallback, timeout(5000)).onChangeEvent(valueCaptor.capture());
assertThat(valueCaptor.getAllValues()).containsExactly(goodValue);
}
@Test
public void testUnregisterCallback_doesNothingIfNothingRegistered() throws Exception {
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, VENDOR_STATIC_PROPERTY);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_doesNothingIfNothingRegistered() throws Exception {
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_STATIC_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_doesNothingIfPropertyIsNotRegisteredForCallback()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, VENDOR_STATIC_PROPERTY);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_doesNothingIfNothingIsNotRegisteredForCallback()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_STATIC_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_doesNothingIfCallbackIsNotRegisteredForProperty()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2,
VENDOR_CONTINUOUS_PROPERTY);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_doesNothingIfCallbackIsNotRegisteredForProperty()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_CONTINUOUS_PROPERTY,
mCarPropertyEventCallback2);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_doesNothingIfCarPropertyConfigNull() throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
setPropIdWithoutConfig(VENDOR_CONTINUOUS_PROPERTY);
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_doesNothingIfNoPermission() throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
setPropIdWithoutPermission(VENDOR_CONTINUOUS_PROPERTY);
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_doesNothingIfCarPropertyConfigNull()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
setPropIdWithoutConfig(VENDOR_CONTINUOUS_PROPERTY);
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_CONTINUOUS_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_doesNothingIfNoPermission()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
setPropIdWithoutPermission(VENDOR_CONTINUOUS_PROPERTY);
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_CONTINUOUS_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_unregistersCallbackForSingleProperty()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_unsubscribeCallbackForSingleProperty()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_unregistersCallbackForSpecificProperty()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY);
verify(mICarProperty).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_ignoreUserHalProp()
throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
mCarPropertyManager.unsubscribePropertyEvents(INITIAL_USER_INFO,
mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(), any());
}
@Test
public void testUnregisterCallback_ignoreUserHalProp_beforeU()
throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, INITIAL_USER_INFO);
verify(mICarProperty, never()).unregisterListener(anyInt(), any());
}
@Test
public void testUnregisterCallback_ignoreUserHalProp_afterU()
throws Exception {
setAppTargetSdk(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback, INITIAL_USER_INFO);
verify(mICarProperty, never()).unregisterListener(anyInt(), any());
}
@Test
public void testUnsubscribePropertyEvents_unsubscribeCallbackForSpecificProperty()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY)
.build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
verify(mICarProperty, never()).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_unregistersCallbackForBothProperties()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
verify(mICarProperty, times(2)).unregisterListener(mPropertyIdCaptor.capture(),
any(ICarPropertyEventListener.class));
assertThat(mPropertyIdCaptor.getAllValues()).containsExactly(VENDOR_CONTINUOUS_PROPERTY,
VENDOR_ON_CHANGE_PROPERTY);
}
@Test
public void testUnsubscribePropertyEvents_unsubscribeCallbackForBothProperties()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build(),
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY)
.setUpdateRateNormal().build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_CONTINUOUS_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_unregistersAllCallbackForSingleProperty()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_unsubscribeAllCallbackForSingleProperty()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback2)).isTrue();
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_CONTINUOUS_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty).unregisterListener(eq(VENDOR_CONTINUOUS_PROPERTY),
any(ICarPropertyEventListener.class));
verify(mICarProperty, never()).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_registerCalledIfBiggerRateRemoved() throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
VENDOR_CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback2);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
verify(mICarProperty, times(3)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
FIRST_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
LARGER_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
FIRST_UPDATE_RATE_HZ))
);
}
@Test
public void testUnsubscribePropertyEvents_registerCalledIfBiggerRateRemoved()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(LARGER_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback2)).isTrue();
clearInvocations(mICarProperty);
mCarPropertyManager.unsubscribePropertyEvents(mCarPropertyEventCallback2);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
verify(mICarProperty, times(1)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
FIRST_UPDATE_RATE_HZ, /* enableVur= */ true))
);
}
@Test
public void testUnregisterCallback_registerNotCalledIfSmallerRateRemoved()
throws Exception {
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_CONTINUOUS_PROPERTY, FIRST_UPDATE_RATE_HZ)).isTrue();
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback2,
VENDOR_CONTINUOUS_PROPERTY, LARGER_UPDATE_RATE_HZ)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
verify(mICarProperty, times(2)).registerListener(
mCarSubscriptionCaptor.capture(), any(ICarPropertyEventListener.class));
assertThat(mCarSubscriptionCaptor.getAllValues()).containsExactly(
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
FIRST_UPDATE_RATE_HZ)),
List.of(createCarSubscriptionOption(VENDOR_CONTINUOUS_PROPERTY, new int[]{0},
LARGER_UPDATE_RATE_HZ)));
}
@Test
public void testUnsubscribePropertyEvents_subscribeNotCalledIfSmallerRateremoved()
throws Exception {
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(FIRST_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_CONTINUOUS_PROPERTY)
.setUpdateRateHz(LARGER_UPDATE_RATE_HZ).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback2)).isTrue();
clearInvocations(mICarProperty);
mCarPropertyManager.unsubscribePropertyEvents(mCarPropertyEventCallback2);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_doesNothingWithPropertyIdIfNothingRegistered()
throws Exception {
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_doesNothingWithPropertyIdIfNothingRegistered()
throws Exception {
mCarPropertyManager.unsubscribePropertyEvents(mCarPropertyEventCallback);
verify(mICarProperty, never()).unregisterListener(anyInt(),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_returnsVoidForIllegalArgumentException()
throws RemoteException {
doThrow(IllegalArgumentException.class).when(mICarProperty).unregisterListener(
eq(VENDOR_ON_CHANGE_PROPERTY), any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY);
verify(mICarProperty).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_returnsVoidForIllegalArgumentException()
throws Exception {
doThrow(IllegalArgumentException.class).when(mICarProperty).unregisterListener(
eq(VENDOR_ON_CHANGE_PROPERTY), any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY);
verify(mICarProperty).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnregisterCallback_SecurityException() throws Exception {
doThrow(SecurityException.class).when(mICarProperty).unregisterListener(
eq(VENDOR_ON_CHANGE_PROPERTY), any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
assertThrows(SecurityException.class,
() -> mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY));
}
@Test
public void testUnsubscribePropertyEvents_SecurityException() throws Exception {
doThrow(SecurityException.class).when(mICarProperty).unregisterListener(
eq(VENDOR_ON_CHANGE_PROPERTY), any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
assertThrows(SecurityException.class,
() -> mCarPropertyManager.unsubscribePropertyEvents(VENDOR_ON_CHANGE_PROPERTY,
mCarPropertyEventCallback));
}
@Test
public void testUnregisterCallback_recoversAfterSecurityException() throws Exception {
doThrow(SecurityException.class).doNothing().when(mICarProperty).unregisterListener(
eq(VENDOR_ON_CHANGE_PROPERTY), any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.registerCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY, CarPropertyManager.SENSOR_RATE_ONCHANGE)).isTrue();
assertThrows(SecurityException.class,
() -> mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY));
mCarPropertyManager.unregisterCallback(mCarPropertyEventCallback,
VENDOR_ON_CHANGE_PROPERTY);
verify(mICarProperty, times(2)).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testUnsubscribePropertyEvents_recoversAfterSecurityException() throws Exception {
doThrow(SecurityException.class).doNothing().when(mICarProperty).unregisterListener(
eq(VENDOR_ON_CHANGE_PROPERTY), any(ICarPropertyEventListener.class));
assertThat(mCarPropertyManager.subscribePropertyEvents(List.of(
new Subscription.Builder(VENDOR_ON_CHANGE_PROPERTY).build()),
/* callbackExecutor= */ null, mCarPropertyEventCallback)).isTrue();
assertThrows(SecurityException.class,
() -> mCarPropertyManager.unsubscribePropertyEvents(VENDOR_ON_CHANGE_PROPERTY,
mCarPropertyEventCallback));
mCarPropertyManager.unsubscribePropertyEvents(VENDOR_ON_CHANGE_PROPERTY,
mCarPropertyEventCallback);
verify(mICarProperty, times(2)).unregisterListener(eq(VENDOR_ON_CHANGE_PROPERTY),
any(ICarPropertyEventListener.class));
}
@Test
public void testOnErrorEvent_callbackIsCalledWithErrorEvent() throws RemoteException {
List eventList = createErrorCarPropertyEventList();
CarPropertyConfig config = CarPropertyConfig.newBuilder(Float.class, HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build()).build();
addCarPropertyConfig(config);
ICarPropertyEventListener listener = getCarPropertyEventListener();
listener.onEvent(eventList);
// Wait until we get the on error event for the initial value.
verify(mCarPropertyEventCallback, timeout(5000)).onErrorEvent(HVAC_TEMPERATURE_SET, 0,
CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN);
}
@Test
public void testOnChangeEvent_callbackIsCalledWithEvent() throws RemoteException {
List eventList = createCarPropertyEventList();
CarPropertyConfig config = CarPropertyConfig.newBuilder(Float.class, HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build()).build();
addCarPropertyConfig(config);
ICarPropertyEventListener listener = getCarPropertyEventListener();
ArgumentCaptor value = ArgumentCaptor.forClass(CarPropertyValue.class);
listener.onEvent(eventList);
// Wait until we get the on property change event for the initial value.
verify(mCarPropertyEventCallback, timeout(5000)).onChangeEvent(value.capture());
assertThat(value.getValue().getPropertyId()).isEqualTo(HVAC_TEMPERATURE_SET);
assertThat(value.getValue().getValue()).isEqualTo(17.0f);
}
private ICarPropertyEventListener getCarPropertyEventListener() throws RemoteException {
ArgumentCaptor carPropertyEventListenerArgumentCaptor =
ArgumentCaptor.forClass(ICarPropertyEventListener.class);
mCarPropertyManager.registerCallback(mCarPropertyEventCallback, HVAC_TEMPERATURE_SET,
SENSOR_RATE_ONCHANGE);
verify(mICarProperty).registerListener(eq(List.of(
createCarSubscriptionOption(HVAC_TEMPERATURE_SET, new int[]{0},
SENSOR_RATE_ONCHANGE))),
carPropertyEventListenerArgumentCaptor.capture());
return carPropertyEventListenerArgumentCaptor.getValue();
}
@Test
public void testGetPropertyList() throws Exception {
List expectedConfigs = mock(List.class);
when(mICarProperty.getPropertyList())
.thenReturn(new CarPropertyConfigList(expectedConfigs));
assertThat(mCarPropertyManager.getPropertyList()).isEqualTo(expectedConfigs);
}
@Test
public void testGetPropertyList_withPropertyIds() throws Exception {
ArraySet requestedPropertyIds = new ArraySet<>(Set.of(
VENDOR_CONTINUOUS_PROPERTY, HVAC_TEMPERATURE_SET));
CarPropertyConfig config1 = CarPropertyConfig.newBuilder(Integer.class,
VENDOR_CONTINUOUS_PROPERTY,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build()).build();
CarPropertyConfig config2 = CarPropertyConfig.newBuilder(Float.class,
HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build()).build();
addCarPropertyConfig(config1);
addCarPropertyConfig(config2);
assertThat(mCarPropertyManager.getPropertyList(requestedPropertyIds))
.containsExactly(config1, config2);
}
@Test
public void testGetPropertyList_filterUnsupportedPropertyIds() throws Exception {
ArraySet requestedPropertyIds = new ArraySet<>(Set.of(
0, 1, VENDOR_CONTINUOUS_PROPERTY, HVAC_TEMPERATURE_SET));
CarPropertyConfig config1 = CarPropertyConfig.newBuilder(Integer.class,
VENDOR_CONTINUOUS_PROPERTY,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build()).build();
CarPropertyConfig config2 = CarPropertyConfig.newBuilder(Float.class,
HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.addAreaIdConfig(new AreaIdConfig.Builder(0).build()).build();
addCarPropertyConfig(config1);
addCarPropertyConfig(config2);
assertThat(mCarPropertyManager.getPropertyList(requestedPropertyIds))
.containsExactly(config1, config2);
}
@Test
public void testGetCarPropertyConfig() throws Exception {
assertThat(mCarPropertyManager.getCarPropertyConfig(VENDOR_ON_CHANGE_PROPERTY))
.isEqualTo(mOnChangeCarPropertyConfig);
}
@Test
public void testGetCarPropertyConfig_noConfigReturned_notSupported() throws Exception {
setPropIdWithoutConfig(HVAC_TEMPERATURE_SET);
assertThat(mCarPropertyManager.getCarPropertyConfig(HVAC_TEMPERATURE_SET)).isNull();
}
@Test
public void testGetCarPropertyConfig_noConfigReturned_noPermission() throws Exception {
setPropIdWithoutPermission(HVAC_TEMPERATURE_SET);
assertThat(mCarPropertyManager.getCarPropertyConfig(HVAC_TEMPERATURE_SET)).isNull();
}
@Test
public void testGetCarPropertyConfig_unsupported() throws Exception {
assertThat(mCarPropertyManager.getCarPropertyConfig(/* propId= */ 0)).isNull();
}
@Test
public void testGetAreaId_global() throws Exception {
assertThat(mCarPropertyManager.getAreaId(VENDOR_ON_CHANGE_PROPERTY, 0)).isEqualTo(0);
}
@Test
public void testGetAreaId_withArea() throws Exception {
int areaId = VehicleAreaSeat.SEAT_ROW_1_LEFT | VehicleAreaSeat.SEAT_ROW_1_CENTER;
CarPropertyConfig config1 = CarPropertyConfig.newBuilder(Integer.class,
HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_SEAT)
.addAreaIdConfig(new AreaIdConfig.Builder(areaId)
.build()).build();
addCarPropertyConfig(config1);
assertThat(mCarPropertyManager.getAreaId(
HVAC_TEMPERATURE_SET, VehicleAreaSeat.SEAT_ROW_1_LEFT)).isEqualTo(areaId);
assertThat(mCarPropertyManager.getAreaId(
HVAC_TEMPERATURE_SET, VehicleAreaSeat.SEAT_ROW_1_CENTER)).isEqualTo(areaId);
}
@Test
public void testGetAreaId_areaNotSupported() throws Exception {
int areaId = VehicleAreaSeat.SEAT_ROW_1_LEFT | VehicleAreaSeat.SEAT_ROW_1_CENTER;
CarPropertyConfig config1 = CarPropertyConfig.newBuilder(Integer.class,
HVAC_TEMPERATURE_SET,
VehicleAreaType.VEHICLE_AREA_TYPE_SEAT)
.addAreaIdConfig(new AreaIdConfig.Builder(areaId)
.build()).build();
addCarPropertyConfig(config1);
assertThrows(IllegalArgumentException.class, () -> mCarPropertyManager.getAreaId(
HVAC_TEMPERATURE_SET, VehicleAreaSeat.SEAT_ROW_1_RIGHT));
}
@Test
public void testGetAreaId_propertyNotSupported() throws Exception {
setPropIdWithoutConfig(HVAC_TEMPERATURE_SET);
assertThrows(IllegalArgumentException.class, () -> mCarPropertyManager.getAreaId(
HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetAreaId_noPermissionToProperty() throws Exception {
setPropIdWithoutPermission(HVAC_TEMPERATURE_SET);
assertThrows(IllegalArgumentException.class, () -> mCarPropertyManager.getAreaId(
HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testGetAreaId_remoteExceptionFromCarService() throws Exception {
when(mICarProperty.getPropertyConfigList(new int[]{HVAC_TEMPERATURE_SET}))
.thenThrow(new RemoteException());
assertThrows(IllegalArgumentException.class, () -> mCarPropertyManager.getAreaId(
HVAC_TEMPERATURE_SET, 0));
}
@Test
public void testIsPropertyAvailable_withValueWithNotAvailableStatus() throws Exception {
CarPropertyValue value = new CarPropertyValue<>(HVAC_TEMPERATURE_SET, 0,
CarPropertyValue.STATUS_ERROR, TEST_TIMESTAMP, 17.0f);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(value);
assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
.isFalse();
}
@Test
public void testIsPropertyAvailable() throws Exception {
CarPropertyValue expectedValue = new CarPropertyValue<>(HVAC_TEMPERATURE_SET,
/* areaId= */ 0, CarPropertyValue.STATUS_AVAILABLE, /* timestamp= */ 0,
/* value= */ 1);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenReturn(expectedValue);
assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
.isTrue();
}
@Test
public void testIsPropertyAvailable_syncOpTryAgain() throws Exception {
CarPropertyValue expectedValue = new CarPropertyValue<>(HVAC_TEMPERATURE_SET,
/* areaId= */ 0, CarPropertyValue.STATUS_AVAILABLE, /* timestamp= */ 0,
/* value= */ 1);
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(SYNC_OP_LIMIT_TRY_AGAIN)).thenReturn(expectedValue);
assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
.isTrue();
verify(mICarProperty, times(2)).getProperty(HVAC_TEMPERATURE_SET, 0);
}
@Test
public void testIsPropertyAvailable_notAvailable() throws Exception {
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_NOT_AVAILABLE));
assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
.isFalse();
}
@Test
public void testIsPropertyAvailable_tryAgain() throws Exception {
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN));
assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
.isFalse();
}
@Test
public void testIsPropertyAvailable_RemoteException() throws Exception {
when(mICarProperty.getProperty(HVAC_TEMPERATURE_SET, 0)).thenThrow(
new RemoteException());
assertThat(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, /* areaId= */ 0))
.isFalse();
}
@Test
public void testIsPropertyAvailable_unsupported() throws Exception {
assertThat(mCarPropertyManager.isPropertyAvailable(/* propId= */ 0, /* areaId= */ 0))
.isFalse();
}
@Test
public void testGetCarPropertyConfig_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getCarPropertyConfig(INITIAL_USER_INFO));
}
@Test
public void testGetPropertyList_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getPropertyList(
new ArraySet(Set.of(HVAC_TEMPERATURE_SET, INITIAL_USER_INFO))));
}
@Test
public void testGetAreaId_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getAreaId(INITIAL_USER_INFO, /* area= */ 0));
}
@Test
public void testGetReadPermission_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getReadPermission(INITIAL_USER_INFO));
}
@Test
public void testGetWritePermission_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getWritePermission(INITIAL_USER_INFO));
}
@Test
public void testIsPropertyAvailable_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.isPropertyAvailable(INITIAL_USER_INFO, /* areaId= */ 0));
}
@Test
public void testGetProperty_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getProperty(INITIAL_USER_INFO, /* areaId= */ 0));
}
@Test
public void testGetBooleanProperty_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.getBooleanProperty(INITIAL_USER_INFO, /* areaId= */ 0));
}
@Test
public void testSetBooleanProperty_userHalProperty() throws Exception {
setAppTargetSdk(Build.VERSION_CODES.TIRAMISU);
assertThrows(IllegalArgumentException.class,
() -> mCarPropertyManager.setBooleanProperty(INITIAL_USER_INFO, /* areaId= */ 0,
true));
}
}