Merge "Import translations. DO NOT MERGE"
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index c1c0e63..bab3b88 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -533,7 +533,9 @@
 package android.car.hardware.property {
 
   public class CarPropertyManager {
+    method public int getAreaId(int, int);
     method public boolean getBooleanProperty(int, int);
+    method @Nullable public android.car.hardware.CarPropertyConfig<?> getCarPropertyConfig(int);
     method public float getFloatProperty(int, int);
     method @NonNull public int[] getIntArrayProperty(int, int);
     method public int getIntProperty(int, int);
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index f3fb100..3bf0f5d 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -61,6 +61,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
 import android.util.Log;
 
@@ -1462,7 +1463,12 @@
 
     /** @hide */
     void handleRemoteExceptionFromCarService(RemoteException e) {
-        Log.w(TAG_CAR, "Car service has crashed", e);
+        if (e instanceof TransactionTooLargeException) {
+            Log.w(TAG_CAR, "Car service threw TransactionTooLargeException", e);
+            throw new CarTransactionException(e, "Car service threw TransactionTooLargException");
+        } else {
+            Log.w(TAG_CAR, "Car service has crashed", e);
+        }
     }
 
 
@@ -1498,10 +1504,18 @@
 
     /** @hide */
     public static  void handleRemoteExceptionFromCarService(Service service, RemoteException e) {
-        Log.w(TAG_CAR,
-                "Car service has crashed, client:" + service.getPackageName() + ","
-                        + service.getClass().getSimpleName(), e);
-        service.stopSelf();
+        if (e instanceof TransactionTooLargeException) {
+            Log.w(TAG_CAR, "Car service threw TransactionTooLargeException, client:"
+                    + service.getPackageName() + ","
+                    + service.getClass().getSimpleName(), e);
+            throw new CarTransactionException(e, "Car service threw TransactionTooLargeException, "
+                + "client: %s, %s", service.getPackageName(), service.getClass().getSimpleName());
+        } else {
+            Log.w(TAG_CAR, "Car service has crashed, client:"
+                    + service.getPackageName() + ","
+                    + service.getClass().getSimpleName(), e);
+            service.stopSelf();
+        }
     }
 
     @Nullable
diff --git a/car-lib/src/android/car/CarTransactionException.java b/car-lib/src/android/car/CarTransactionException.java
new file mode 100644
index 0000000..c0e7e2f
--- /dev/null
+++ b/car-lib/src/android/car/CarTransactionException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car;
+
+/**
+ * Runtime exception thrown when a transaction-level binder exception has occurred.
+ *
+ * This allows clients to log or recover transaction errors as appropriate.
+ *
+ * @hide
+ */
+public class CarTransactionException extends UnsupportedOperationException {
+    CarTransactionException(Throwable cause, String msg, Object... args) {
+        super(String.format(msg, args), cause);
+    }
+}
+
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index e3651da..9419d6d 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.car.Car;
 import android.car.CarManagerBase;
+import android.car.VehicleAreaType;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.os.Handler;
@@ -317,6 +318,47 @@
     }
 
     /**
+     * Get CarPropertyConfig by property Id.
+     *
+     * @param propId Property ID
+     * @return {@link CarPropertyConfig} for the selected property.
+     * Null if the property is not available.
+     */
+    @Nullable
+    public CarPropertyConfig<?> getCarPropertyConfig(int propId) {
+        return  mConfigMap.get(propId);
+    }
+
+    /**
+     * Returns areaId contains the seletcted area for the property.
+     *
+     * @param propId Property ID
+     * @param area Area enum such as Enums in {@link android.car.VehicleAreaSeat}.
+     * @throws IllegalArgumentException if the property is not available in the vehicle for
+     * the selected area.
+     * @return AreaId contains the selected area for the property.
+     */
+    public int getAreaId(int propId, int area) {
+        CarPropertyConfig<?> propConfig = getCarPropertyConfig(propId);
+        if (propConfig == null) {
+            throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
+                    + " is not available");
+        }
+        // For the global property, areaId is 0
+        if (propConfig.isGlobalProperty()) {
+            return VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+        }
+        for (int areaId : propConfig.getAreaIds()) {
+            if ((area & areaId) == area) {
+                return areaId;
+            }
+        }
+
+        throw new IllegalArgumentException("The property propId: 0x" + toHexString(propId)
+                + " is not available at the area: 0x" + toHexString(area));
+    }
+
+    /**
      * Return read permission string for given property ID.
      *
      * @param propId Property ID to query
diff --git a/service/src/com/android/car/VmsLayersAvailability.java b/service/src/com/android/car/VmsLayersAvailability.java
index 2e17a89..a9bbc7a 100644
--- a/service/src/com/android/car/VmsLayersAvailability.java
+++ b/service/src/com/android/car/VmsLayersAvailability.java
@@ -109,9 +109,6 @@
             mPotentialLayersAndPublishers.clear();
             mAvailableAssociatedLayers = Collections.EMPTY_SET;
             mUnavailableAssociatedLayers = Collections.EMPTY_SET;
-            if (mSeq + 1 < mSeq) {
-                throw new IllegalStateException("Sequence is about to loop");
-            }
             mSeq += 1;
         }
     }
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java
index a03e822..b14ea94 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/WifiTetherApBandPreferenceController.java
@@ -129,7 +129,7 @@
 
     private boolean is5GhzBandSupported() {
         final String countryCode = mWifiManager.getCountryCode();
-        if (!mWifiManager.isDualBandSupported() || countryCode == null) {
+        if (!mWifiManager.is5GHzBandSupported() || countryCode == null) {
             return false;
         }
         return true;
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
index eef9638..56540dd 100644
--- a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
@@ -17,10 +17,12 @@
 package com.android.car;
 
 import android.car.Car;
+import android.car.VehicleAreaType;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
 import android.hardware.automotive.vehicle.V2_0.VehicleArea;
+import android.hardware.automotive.vehicle.V2_0.VehicleAreaSeat;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
@@ -67,9 +69,17 @@
     private static final Object[] EXPECTED_VALUE_2 = {"android", true, 3, 1.1f, 2f};
 
     private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_1 =
-            0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL;
+            0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.SEAT;
     private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_2 =
             0x1102 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL;
+    // Use FAKE_PROPERTY_ID to test api return null or throw exception.
+    private static final int FAKE_PROPERTY_ID = 0x111;
+
+    private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT
+                                                    | VehicleAreaSeat.ROW_2_LEFT;
+    private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT
+                                                    | VehicleAreaSeat.ROW_2_CENTER
+                                                    | VehicleAreaSeat.ROW_2_RIGHT;
 
     private CarPropertyManager mManager;
 
@@ -116,14 +126,49 @@
         Assert.assertArrayEquals(EXPECTED_VALUE_2, result.getValue());
     }
 
+    @Test
+    public void testGetPropertyConfig() {
+        CarPropertyConfig config = mManager.getCarPropertyConfig(CUSTOM_GLOBAL_MIXED_PROP_ID_1);
+        Assert.assertEquals(CUSTOM_GLOBAL_MIXED_PROP_ID_1, config.getPropertyId());
+        // return null if can not find the propertyConfig for the property.
+        Assert.assertNull(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID));
+    }
+
+    @Test
+    public void testGetAreaId() {
+        int result = mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_1_LEFT);
+        Assert.assertEquals(DRIVER_SIDE_AREA_ID, result);
+
+        //test for the GLOBAL property
+        int globalAreaId =
+                mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_2, VehicleAreaSeat.ROW_1_LEFT);
+        Assert.assertEquals(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, globalAreaId);
+
+        //test exception
+        try {
+            int areaId = mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_1,
+                    VehicleAreaSeat.ROW_3_CENTER);
+            Assert.fail("Unexpected areaId: " + areaId);
+        } catch (IllegalArgumentException e) {
+            Log.v(TAG, e.getMessage());
+        }
+
+        try {
+            // test exception
+            int areaIdForFakeProp = mManager.getAreaId(FAKE_PROPERTY_ID,
+                    VehicleAreaSeat.ROW_1_LEFT);
+            Assert.fail("Unexpected areaId for fake property: " + areaIdForFakeProp);
+        } catch (IllegalArgumentException e) {
+            Log.v(TAG, e.getMessage());
+        }
+    }
 
     @Override
     protected synchronized void configureMockedHal() {
         PropertyHandler handler = new PropertyHandler();
-        addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1);
+        addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1)
+                .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID);
         addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_2, handler).setConfigArray(CONFIG_ARRAY_2);
-
-
     }
 
     private class PropertyHandler implements VehicleHalPropertyHandler {