Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package android.car.cts;
     17 
     18 import static java.lang.Integer.toHexString;
     19 
     20 import static org.junit.Assert.assertEquals;
     21 import static org.junit.Assert.assertFalse;
     22 import static org.junit.Assert.assertNotEquals;
     23 import static org.junit.Assert.assertNotNull;
     24 
     25 import android.car.Car;
     26 import android.car.VehicleAreaType;
     27 import android.car.VehiclePropertyIds;
     28 import android.car.hardware.CarPropertyConfig;
     29 import android.car.hardware.CarPropertyValue;
     30 import android.car.hardware.property.CarPropertyManager;
     31 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
     32 import android.platform.test.annotations.RequiresDevice;
     33 
     34 import androidx.test.runner.AndroidJUnit4;
     35 
     36 import static com.google.common.truth.Truth.assertThat;
     37 import static org.junit.Assert.assertTrue;
     38 
     39 import android.test.suitebuilder.annotation.SmallTest;
     40 import android.util.ArraySet;
     41 import android.util.Log;
     42 import android.util.SparseArray;
     43 import com.android.internal.annotations.GuardedBy;
     44 import java.util.List;
     45 import org.junit.Assert;
     46 import org.junit.Before;
     47 import org.junit.Test;
     48 import org.junit.runner.RunWith;
     49 
     50 @SmallTest
     51 @RequiresDevice
     52 @RunWith(AndroidJUnit4.class)
     53 public class CarPropertyManagerTest extends CarApiTestBase {
     54 
     55     private static final String TAG = CarPropertyManagerTest.class.getSimpleName();
     56     private static final long WAIT_CALLBACK = 1500L;
     57     private CarPropertyManager mCarPropertyManager;
     58     /** contains property Ids for the properties required by CDD*/
     59     private ArraySet<Integer> mPropertyIds = new ArraySet<>();
     60 
     61 
     62     private static class CarPropertyEventCounter implements CarPropertyEventCallback {
     63         private final Object mLock = new Object();
     64 
     65         @GuardedBy("mLock")
     66         private SparseArray<Integer> mEventCounter = new SparseArray<>();
     67 
     68         @GuardedBy("mLock")
     69         private SparseArray<Integer> mErrorCounter = new SparseArray<>();
     70 
     71         public int receivedEvent(int propId) {
     72             int val;
     73             synchronized (mLock) {
     74                 val = mEventCounter.get(propId, 0);
     75             }
     76             return val;
     77         }
     78 
     79         public int receivedError(int propId) {
     80             int val;
     81             synchronized (mLock) {
     82                 val = mErrorCounter.get(propId, 0);
     83             }
     84             return val;
     85         }
     86 
     87         @Override
     88         public void onChangeEvent(CarPropertyValue value) {
     89             synchronized (mLock) {
     90                 int val = mEventCounter.get(value.getPropertyId(), 0) + 1;
     91                 mEventCounter.put(value.getPropertyId(), val);
     92             }
     93         }
     94 
     95         @Override
     96         public void onErrorEvent(int propId, int zone) {
     97             synchronized (mLock) {
     98                 int val = mErrorCounter.get(propId, 0) + 1;
     99                 mErrorCounter.put(propId, val);
    100             }
    101         }
    102     }
    103 
    104     @Before
    105     public void setUp() throws Exception {
    106         super.setUp();
    107         mCarPropertyManager = (CarPropertyManager) getCar().getCarManager(Car.PROPERTY_SERVICE);
    108         mPropertyIds.add(VehiclePropertyIds.PERF_VEHICLE_SPEED);
    109         mPropertyIds.add(VehiclePropertyIds.GEAR_SELECTION);
    110         mPropertyIds.add(VehiclePropertyIds.NIGHT_MODE);
    111     }
    112 
    113     @Test
    114     public void testGetPropertyList() {
    115         List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList();
    116         assertNotNull(allConfigs);
    117         List<CarPropertyConfig> requiredConfigs = mCarPropertyManager.getPropertyList(mPropertyIds);
    118         // Vehicles need to implement all of those properties
    119         assertEquals(mPropertyIds.size(), requiredConfigs.size());
    120 
    121     }
    122 
    123     @SuppressWarnings("unchecked")
    124     @Test
    125     public void testGetProperty() {
    126         List<CarPropertyConfig> configs = mCarPropertyManager.getPropertyList(mPropertyIds);
    127         for (CarPropertyConfig cfg : configs) {
    128             if (cfg.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ) {
    129                 int[] areaIds = getAreaIdsHelper(cfg);
    130                 int propId = cfg.getPropertyId();
    131                 // no guarantee if we can get values, just call and check if it throws exception.
    132                 if (cfg.getPropertyType() == Boolean.class) {
    133                     for (int areaId : areaIds) {
    134                         mCarPropertyManager.getBooleanProperty(propId, areaId);
    135                     }
    136                 } else if (cfg.getPropertyType() == Integer.class) {
    137                     for (int areaId : areaIds) {
    138                         mCarPropertyManager.getIntProperty(propId, areaId);
    139                     }
    140                 } else if (cfg.getPropertyType() == Float.class) {
    141                     for (int areaId : areaIds) {
    142                         mCarPropertyManager.getFloatProperty(propId, areaId);
    143                     }
    144                 } else if (cfg.getPropertyType() == Integer[].class) {
    145                     for (int areId : areaIds) {
    146                         mCarPropertyManager.getIntArrayProperty(propId, areId);
    147                     }
    148                 } else {
    149                     for (int areaId : areaIds) {
    150                         mCarPropertyManager.getProperty(
    151                                 cfg.getPropertyType(), propId, areaId);;
    152                     }
    153                 }
    154             }
    155         }
    156     }
    157 
    158     @Test
    159     public void testIsPropertyAvailable() {
    160         List<CarPropertyConfig> configs = mCarPropertyManager.getPropertyList(mPropertyIds);
    161 
    162         for (CarPropertyConfig cfg : configs) {
    163             int[] areaIds = getAreaIdsHelper(cfg);
    164             for (int areaId : areaIds) {
    165                 assertTrue(mCarPropertyManager.isPropertyAvailable(cfg.getPropertyId(), areaId));
    166             }
    167         }
    168     }
    169 
    170     @Test
    171     public void testSetProperty() {
    172         List<CarPropertyConfig> configs = mCarPropertyManager.getPropertyList();
    173         for (CarPropertyConfig cfg : configs) {
    174             if (cfg.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE
    175                     && cfg.getPropertyType() == Boolean.class) {
    176                 // Get the current value, and set a different value to the property and verify it.
    177                 for (int areaId : getAreaIdsHelper(cfg)) {
    178                     assertTrue(setBooleanPropertyHelper(cfg.getPropertyId(), areaId));
    179                 }
    180             }
    181         }
    182     }
    183 
    184 
    185     @Test
    186     public void testRegisterCallback() throws Exception {
    187         //Test on registering a invalid property
    188         int invalidPropertyId = -1;
    189         boolean isRegistered = mCarPropertyManager.registerCallback(
    190             new CarPropertyEventCounter(), invalidPropertyId, 0);
    191         assertFalse(isRegistered);
    192 
    193         // Test for continuous properties
    194         int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED;
    195         CarPropertyEventCounter speedListenerNormal = new CarPropertyEventCounter();
    196         CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter();
    197 
    198         assertEquals(0, speedListenerNormal.receivedEvent(vehicleSpeed));
    199         assertEquals(0, speedListenerNormal.receivedError(vehicleSpeed));
    200         assertEquals(0, speedListenerUI.receivedEvent(vehicleSpeed));
    201         assertEquals(0, speedListenerUI.receivedError(vehicleSpeed));
    202 
    203         mCarPropertyManager.registerCallback(speedListenerNormal, vehicleSpeed,
    204                 CarPropertyManager.SENSOR_RATE_NORMAL);
    205         mCarPropertyManager.registerCallback(speedListenerUI, vehicleSpeed,
    206                 CarPropertyManager.SENSOR_RATE_FASTEST);
    207 
    208         Thread.sleep(WAIT_CALLBACK);
    209         assertNotEquals(0, speedListenerNormal.receivedEvent(vehicleSpeed));
    210         assertNotEquals(0, speedListenerUI.receivedEvent(vehicleSpeed));
    211         assertTrue(speedListenerUI.receivedEvent(vehicleSpeed) >
    212                 speedListenerNormal.receivedEvent(vehicleSpeed));
    213 
    214         mCarPropertyManager.unregisterCallback(speedListenerUI);
    215         mCarPropertyManager.unregisterCallback(speedListenerNormal);
    216 
    217         // Test for on_change properties
    218         int nightMode = VehiclePropertyIds.NIGHT_MODE;
    219         CarPropertyEventCounter nightModeListener = new CarPropertyEventCounter();
    220         mCarPropertyManager.registerCallback(nightModeListener, nightMode, 0);
    221         Thread.sleep(WAIT_CALLBACK);
    222         assertEquals(1, nightModeListener.receivedEvent(nightMode));
    223 
    224         mCarPropertyManager.unregisterCallback(nightModeListener);
    225 
    226     }
    227 
    228     @Test
    229     public void testUnregisterCallback() throws Exception {
    230 
    231         int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED;
    232         CarPropertyEventCounter speedListenerNormal = new CarPropertyEventCounter();
    233         CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter();
    234 
    235         mCarPropertyManager.registerCallback(speedListenerNormal, vehicleSpeed,
    236             CarPropertyManager.SENSOR_RATE_NORMAL);
    237 
    238         // test on unregistering a callback that was never registered
    239         try {
    240             mCarPropertyManager.unregisterCallback(speedListenerUI);
    241         } catch (Exception e) {
    242             Assert.fail();
    243         }
    244 
    245         mCarPropertyManager.registerCallback(speedListenerUI, vehicleSpeed,
    246             CarPropertyManager.SENSOR_RATE_UI);
    247         Thread.sleep(WAIT_CALLBACK);
    248 
    249         mCarPropertyManager.unregisterCallback(speedListenerNormal, vehicleSpeed);
    250         Thread.sleep(WAIT_CALLBACK);
    251 
    252         int currentEventNormal = speedListenerNormal.receivedEvent(vehicleSpeed);
    253         int currentEventUI = speedListenerUI.receivedEvent(vehicleSpeed);
    254         Thread.sleep(WAIT_CALLBACK);
    255 
    256         assertEquals(currentEventNormal, speedListenerNormal.receivedEvent(vehicleSpeed));
    257         assertNotEquals(currentEventUI, speedListenerUI.receivedEvent(vehicleSpeed));
    258 
    259         mCarPropertyManager.unregisterCallback(speedListenerUI);
    260         Thread.sleep(WAIT_CALLBACK);
    261 
    262         currentEventUI = speedListenerUI.receivedEvent(vehicleSpeed);
    263         Thread.sleep(WAIT_CALLBACK);
    264         assertEquals(currentEventUI, speedListenerUI.receivedEvent(vehicleSpeed));
    265     }
    266 
    267     /**
    268      * Returns true if set boolean value successfully.
    269      * @param propId
    270      * @param areaId
    271      * @return
    272      */
    273     private boolean setBooleanPropertyHelper(int propId, int areaId) {
    274         boolean currentValue = mCarPropertyManager.getBooleanProperty(propId, areaId);
    275         boolean expectedValue = !currentValue;
    276         try {
    277             mCarPropertyManager.setBooleanProperty(propId, areaId, expectedValue);
    278             Thread.sleep(WAIT_CALLBACK);
    279             currentValue = mCarPropertyManager.getBooleanProperty(propId, areaId);
    280             return expectedValue == currentValue;
    281         } catch (Exception e) {
    282             Log.e(TAG, new StringBuilder()
    283                         .append("Failed to verify Property Id: 0x")
    284                         .append(toHexString(propId))
    285                         .append(", in areaId: 0x")
    286                         .append(toHexString(areaId))
    287                         .toString());
    288         }
    289         return false;
    290     }
    291 
    292     private int[] getAreaIdsHelper(CarPropertyConfig config) {
    293         if (config.isGlobalProperty()) {
    294             int[] areaIds = {0};
    295             return areaIds;
    296         } else {
    297             return config.getAreaIds();
    298         }
    299     }
    300 
    301 }
    302