Returns default value in CarInfoManager

Catch the exception and returns default value when the sensor is not
available in CarInfoManager

Bug: 184436663
Bug: 188887945
Test: atest CarInfoManager
Change-Id: I8f43c8881dac9bdef6ac4ea82021bc13be574277
diff --git a/car-lib/src/android/car/CarInfoManager.java b/car-lib/src/android/car/CarInfoManager.java
index 6b2ddd7..32d4a81 100644
--- a/car-lib/src/android/car/CarInfoManager.java
+++ b/car-lib/src/android/car/CarInfoManager.java
@@ -23,6 +23,9 @@
 import android.car.hardware.property.ICarProperty;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.Slog;
+
+import java.util.Arrays;
 
 
 /**
@@ -31,6 +34,8 @@
  */
 public final class CarInfoManager extends CarManagerBase {
 
+    private static final String TAG = CarInfoManager.class.getSimpleName();
+
     private final CarPropertyManager mCarPropertyMgr;
     /**
      * Key for manufacturer of the car. Passed in basic info Bundle.
@@ -115,9 +120,7 @@
      */
     @NonNull
     public String getManufacturer() {
-        CarPropertyValue<String> carProp = mCarPropertyMgr.getProperty(String.class,
-                BASIC_INFO_KEY_MANUFACTURER, 0);
-        return carProp != null ? carProp.getValue() : "";
+        return  getPropertyWithDefaultValue(String.class, BASIC_INFO_KEY_MANUFACTURER, "");
     }
 
     /**
@@ -127,9 +130,7 @@
      */
     @NonNull
     public String getModel() {
-        CarPropertyValue<String> carProp = mCarPropertyMgr.getProperty(
-                String.class, BASIC_INFO_KEY_MODEL, 0);
-        return carProp != null ? carProp.getValue() : "";
+        return getPropertyWithDefaultValue(String.class, BASIC_INFO_KEY_MODEL, "");
     }
 
     /**
@@ -139,7 +140,7 @@
     @Deprecated
     @NonNull
     public String getModelYear() {
-        int year =  mCarPropertyMgr.getIntProperty(BASIC_INFO_KEY_MODEL_YEAR, 0);
+        int year =  getModelYearInInteger();
         return year == 0 ? "" : Integer.toString(year);
     }
 
@@ -147,7 +148,7 @@
      * @return Model year of the car in AD.  0 if not available.
      */
     public int getModelYearInInteger() {
-        return mCarPropertyMgr.getIntProperty(BASIC_INFO_KEY_MODEL_YEAR, 0);
+        return getPropertyWithDefaultValue(Integer.class, BASIC_INFO_KEY_MODEL_YEAR, 0);
     }
 
     /**
@@ -164,7 +165,7 @@
      *         fuel.
      */
     public float getFuelCapacity() {
-        return mCarPropertyMgr.getFloatProperty(BASIC_INFO_FUEL_CAPACITY, 0);
+        return getPropertyWithDefaultValue(Float.class, BASIC_INFO_FUEL_CAPACITY, 0f);
     }
 
     /**
@@ -172,7 +173,9 @@
      * types available.
      */
     public @FuelType.Enum int[] getFuelTypes() {
-        return mCarPropertyMgr.getIntArrayProperty(BASIC_INFO_FUEL_TYPES, 0);
+        Integer[] fuels = getPropertyWithDefaultValue(Integer[].class, BASIC_INFO_FUEL_TYPES,
+                new Integer[]{});
+        return Arrays.stream(fuels).mapToInt(Integer::intValue).toArray();
     }
 
     /**
@@ -180,9 +183,7 @@
      * @return Battery capacity of the car in Watt-Hour(Wh). Return 0 if car doesn't run on battery.
      */
     public float getEvBatteryCapacity() {
-        CarPropertyValue<Float> carProp = mCarPropertyMgr.getProperty(Float.class,
-                BASIC_INFO_EV_BATTERY_CAPACITY, 0);
-        return carProp != null ? carProp.getValue() : 0f;
+        return getPropertyWithDefaultValue(Float.class, BASIC_INFO_EV_BATTERY_CAPACITY, 0f);
     }
 
     /**
@@ -190,8 +191,9 @@
      *         no connector types available.
      */
     public @EvConnectorType.Enum int[] getEvConnectorTypes() {
-        int[] valueInHal =
-                mCarPropertyMgr.getIntArrayProperty(BASIC_INFO_EV_CONNECTOR_TYPES, 0);
+        Integer[] valueInHal = getPropertyWithDefaultValue(Integer[].class,
+                BASIC_INFO_EV_CONNECTOR_TYPES, new Integer[]{});
+
         int[] connectorTypes = new int[valueInHal.length];
         for (int i = 0; i < valueInHal.length; i++) {
             switch (valueInHal[i]) {
@@ -239,24 +241,44 @@
     }
 
     /**
-     * @return Driver seat's location.
+     * @return Driver seat's location. Returns {@link VehicleAreaSeat#SEAT_UNKNOWN} if the sensor
+     * is not available.
      */
     public @VehicleAreaSeat.Enum int getDriverSeat() {
-        return mCarPropertyMgr.getIntProperty(BASIC_INFO_DRIVER_SEAT, 0);
+        return getPropertyWithDefaultValue(Integer.class, BASIC_INFO_DRIVER_SEAT,
+                VehicleAreaSeat.SEAT_UNKNOWN);
     }
 
     /**
-     * @return EV port location of the car.
+     * @return EV port location of the car. Returns {@link PortLocationType#UNKNOWN} if the sensor
+     * is not available.
      */
     public @PortLocationType.Enum int getEvPortLocation() {
-        return mCarPropertyMgr.getIntProperty(BASIC_INFO_EV_PORT_LOCATION, 0);
+        return getPropertyWithDefaultValue(Integer.class, BASIC_INFO_EV_PORT_LOCATION,
+                PortLocationType.UNKNOWN);
     }
 
     /**
-     * @return Fuel door location of the car.
+     * @return Fuel door location of the car.Returns {@link PortLocationType#UNKNOWN} if the sensor
+     * is not available.
      */
     public @PortLocationType.Enum int getFuelDoorLocation() {
-        return mCarPropertyMgr.getIntProperty(BASIC_INFO_FUEL_DOOR_LOCATION, 0);
+        return getPropertyWithDefaultValue(Integer.class, BASIC_INFO_FUEL_DOOR_LOCATION,
+                PortLocationType.UNKNOWN);
+    }
+
+    private <T> T getPropertyWithDefaultValue(Class<T> clazz, int propId, T defaultValue) {
+        try {
+            CarPropertyValue<T> carProp = mCarPropertyMgr.getProperty(
+                    clazz, propId, 0);
+            if (carProp != null && carProp.getStatus() == CarPropertyValue.STATUS_AVAILABLE) {
+                return carProp.getValue();
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Failed to get property value for 0x:" + Integer.toHexString(propId)
+                    + " ,returns default value" + defaultValue);
+        }
+        return defaultValue;
     }
 
     /** @hide */
diff --git a/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java b/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java
index 6f9e2b3..8bbed91 100644
--- a/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarInfoManagerTest.java
@@ -30,7 +30,9 @@
 
 import com.android.car.vehiclehal.VehiclePropValueBuilder;
 
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
@@ -41,6 +43,9 @@
 public class CarInfoManagerTest extends MockedCarTestBase {
     private static final String MAKE_NAME = "ANDROID";
     private static final String MODEL_NAME = "TEST";
+    private static final String DEFAULT_STRING_VALUE = "";
+    private static final int DEFAULT_INTEGER_VALUE = 0;
+    private static final float DEFAULT_FLOAT_VALUE = 0f;
     private static final int MODEL_YEAR = 2020;
     private static final String MODEL_YEAR_STRING = "2020";
     private static final float FAKE_CAPACITY = 2.0f;
@@ -49,9 +54,15 @@
     private static final List<Integer> EV_CONNECTOR_TYPES =
             Arrays.asList(android.car.EvConnectorType.GBT, android.car.EvConnectorType.GBT_DC);
     private CarInfoManager mCarInfoManager;
+    @Rule
+    public TestName mTestName = new TestName();
 
     @Override
     protected synchronized void configureMockedHal() {
+        // test if the sensor is unimplemented in cars.
+        if (mTestName.getMethodName().endsWith("unimplemented")) {
+            return;
+        }
         addStaticProperty(VehicleProperty.INFO_MAKE,
                 VehiclePropValueBuilder.newBuilder(VehicleProperty.INFO_MAKE)
                         .setStringValue(MAKE_NAME)
@@ -101,47 +112,95 @@
     }
 
     @Test
+    public void testVehicleId_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getVehicleId()).isEqualTo(DEFAULT_STRING_VALUE);
+    }
+
+    @Test
     public void testManufacturer() throws Exception {
         assertThat(mCarInfoManager.getManufacturer()).isEqualTo(MAKE_NAME);
     }
 
     @Test
+    public void testManufacturer_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getManufacturer()).isEqualTo(DEFAULT_STRING_VALUE);
+    }
+
+    @Test
     public void testGetModel() throws Exception {
         assertThat(mCarInfoManager.getModel()).isEqualTo(MODEL_NAME);
     }
 
     @Test
+    public void testGetModel_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getModel()).isEqualTo(DEFAULT_STRING_VALUE);
+    }
+
+    @Test
     public void testGetFuelType() throws Exception {
         assertThat(mCarInfoManager.getFuelTypes()).asList()
                 .containsAtLeastElementsIn(FUEL_TYPES).inOrder();
     }
 
     @Test
+    public void testGetFuelType_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getFuelTypes()).isEmpty();
+    }
+
+    @Test
     public void testGetEvConnectorTypes() throws Exception {
         assertThat(mCarInfoManager.getEvConnectorTypes()).asList()
                 .containsAtLeastElementsIn(EV_CONNECTOR_TYPES).inOrder();
     }
 
     @Test
+    public void testGetEvConnectorTypes_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getEvConnectorTypes()).isEmpty();
+    }
+
+    @Test
     public void testGetModelYear() throws Exception {
         assertThat(mCarInfoManager.getModelYear()).isEqualTo(MODEL_YEAR_STRING);
         assertThat(mCarInfoManager.getModelYearInInteger()).isEqualTo(MODEL_YEAR);
     }
 
     @Test
+    public void testGetModelYear_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getModelYear()).isEqualTo(DEFAULT_STRING_VALUE);
+        assertThat(mCarInfoManager.getModelYearInInteger()).isEqualTo(DEFAULT_INTEGER_VALUE);
+    }
+
+    @Test
     public void testGetPortDoorLocation() throws Exception {
         assertThat(mCarInfoManager.getEvPortLocation()).isEqualTo(PortLocationType.FRONT);
         assertThat(mCarInfoManager.getFuelDoorLocation()).isEqualTo(PortLocationType.FRONT_LEFT);
     }
 
     @Test
+    public void testGetPortDoorLocation_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getEvPortLocation()).isEqualTo(PortLocationType.UNKNOWN);
+        assertThat(mCarInfoManager.getFuelDoorLocation()).isEqualTo(PortLocationType.UNKNOWN);
+    }
+
+    @Test
     public void testGetCapacity() throws Exception {
         assertThat(mCarInfoManager.getEvBatteryCapacity()).isEqualTo(FAKE_CAPACITY);
         assertThat(mCarInfoManager.getFuelCapacity()).isEqualTo(FAKE_CAPACITY);
     }
 
     @Test
+    public void testGetCapacity_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getEvBatteryCapacity()).isEqualTo(DEFAULT_FLOAT_VALUE);
+        assertThat(mCarInfoManager.getFuelCapacity()).isEqualTo(DEFAULT_FLOAT_VALUE);
+    }
+
+    @Test
     public void testGetDriverSeat() throws Exception {
         assertThat(mCarInfoManager.getDriverSeat()).isEqualTo(VehicleAreaSeat.SEAT_ROW_1_LEFT);
     }
+
+    @Test
+    public void testGetDriverSeat_unimplemented() throws Exception {
+        assertThat(mCarInfoManager.getDriverSeat()).isEqualTo(VehicleAreaSeat.SEAT_UNKNOWN);
+    }
 }