Merge "Add vehicle_binding_util to car builds" into sc-v2-dev
diff --git a/Android.mk b/Android.mk
index 8b1efbf..0d59692 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,5 +15,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+# Include car_ui_portrait
+include $(LOCAL_PATH)/car_product/car_ui_portrait/Android.mk
+
 # Include the sub-makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/car-lib/src/android/car/ICarUserService.aidl b/car-lib/src/android/car/ICarUserService.aidl
index 267044d..bee3bba 100644
--- a/car-lib/src/android/car/ICarUserService.aidl
+++ b/car-lib/src/android/car/ICarUserService.aidl
@@ -40,8 +40,8 @@
     List<UserInfo> getPassengers(int driverId);
     boolean startPassenger(int passengerId, int zoneId);
     boolean stopPassenger(int passengerId);
-    void setLifecycleListenerForUid(in IResultReceiver listener);
-    void resetLifecycleListenerForUid();
+    void setLifecycleListenerForApp(String pkgName, in IResultReceiver listener);
+    void resetLifecycleListenerForApp(in IResultReceiver listener);
     UserIdentificationAssociationResponse getUserIdentificationAssociation(in int[] types);
     void setUserIdentificationAssociation(int timeoutMs, in int[] types, in int[] values,
       in AndroidFuture<UserIdentificationAssociationResponse> result);
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index 67e54c4..1caa78f 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -17,6 +17,7 @@
 package android.car;
 
 import android.annotation.RequiresPermission;
+import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.VehicleElectronicTollCollectionCardStatus;
 import android.car.hardware.property.VehicleElectronicTollCollectionCardType;
 
@@ -38,95 +39,183 @@
     @RequiresPermission(Car.PERMISSION_IDENTIFICATION)
     public static final int INFO_VIN = 286261504;
     /**
-     * Manufacturer of vehicle
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * Manufacturer of vehicle.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code String} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MAKE = 286261505;
     /**
-     * Model of vehicle
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * Model of vehicle.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code String} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MODEL = 286261506;
     /**
      * Model year of vehicle.
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MODEL_YEAR = 289407235;
     /**
-     * Fuel capacity of the vehicle in milliliters
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * Fuel capacity of the vehicle in milliliters.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_CAPACITY = 291504388;
     /**
-     * List of fuels the vehicle may use
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * List the {@link FuelType}s the vehicle may use.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer[]} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_TYPE = 289472773;
     /**
      * Battery capacity of the vehicle in watt-hours (Wh), if EV or hybrid. This is the nominal
      * battery capacity when the vehicle is new.
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EV_BATTERY_CAPACITY = 291504390;
     /**
-     * List of connectors this vehicle may use
+     * List of {@link EvConnectorType}s this vehicle may use.
      *
-     * <p>Applications can query the property value by
-     * {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)}. The
-     * return value is an integer array containing enums in {@link EvConnectorType}
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer[]} property type
+     * </ul>
      *
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EV_CONNECTOR_TYPE = 289472775;
     /**
-     * Fuel door location
+     * {@link PortLocationType} for the fuel door location.
      *
-     * <p> Applications can query the property value by
-     * {@link android.car.hardware.property.CarPropertyManager#getIntProperty(int, int)}. The return
-     * value is one of enums in {@link PortLocationType}.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer} property type
+     * </ul>
      *
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_FUEL_DOOR_LOCATION = 289407240;
     /**
-     * EV port location
+     * {@link PortLocationType} for the EV port location
      *
-     * <p> Applications can query the property value by
-     * {@link android.car.hardware.property.CarPropertyManager#getIntProperty(int, int)}. The return
-     * value is one of enums in {@link PortLocationType}.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer} property type
+     * </ul>
      *
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EV_PORT_LOCATION = 289407241;
     /**
-     * Multiple EV port locations
+     * List {@link PortLocationType}s for Multiple EV port locations.
      *
-     * <p> Applications can query the property value by
-     * {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)}. The
-     * return value is an integer array containing enums in {@link PortLocationType}.
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer[]} property type
+     * </ul>
      *
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_MULTI_EV_PORT_LOCATIONS = 289472780;
     /**
-     * Driver's seat location
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * Driver's {@link VehicleAreaSeat} seat location.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_DRIVER_SEAT = 356516106;
     /**
-     * Vehicle's exterior dimensions.
-     * Requires permission: {@link Car#PERMISSION_CAR_INFO}.
+     * Vehicle's exterior dimensions in millimeters.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}
+     *  <li>{@code Integer[]} property type
+     * </ul>
+     *
+     * <p>Exterior dimensions defined in the {@link CarPropertyValue#getValue()} {@code Integer[]}:
+     * <ul>
+     *  <li>Integer[0] = height
+     *  <li>Integer[1] = length
+     *  <li>Integer[2] = width
+     *  <li>Integer[3] = width including mirrors
+     *  <li>Integer[4] = wheel base
+     *  <li>Integer[5] = track width front
+     *  <li>Integer[6] = track width rear
+     *  <li>Integer[7] = curb to curb turning radius
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_CAR_INFO}.
      */
     @RequiresPermission(Car.PERMISSION_CAR_INFO)
     public static final int INFO_EXTERIOR_DIMENSIONS = 289472779;
@@ -371,11 +460,53 @@
     @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int GEAR_SELECTION = 289408000;
     /**
-     * Current gear. In non-manual case, selected gear may not
-     * match the current gear. For example, if the selected gear is GEAR_DRIVE,
-     * the current gear will be one of GEAR_1, GEAR_2 etc, which reflects
-     * the actual gear the transmission is currently running in.
-     * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
+     * Vehicle transmission's current {@link VehicleGear}.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Integer} property type
+     * </ul>
+     *
+     * <p>{@code CURRENT_GEAR}'s value may not match that of {@link
+     * VehiclePropertyIds#GEAR_SELECTION}. For example, if the {@link
+     * VehiclePropertyIds#GEAR_SELECTION} is {@link VehicleGear#GEAR_DRIVE} in a vehicle with an
+     * automatic transmission, the {@code CURRENT_GEAR} will be one of {@link
+     * VehicleGear#GEAR_FIRST}, {@link VehicleGear#GEAR_SECOND}, etc, which reflects the actual gear
+     * the transmission is currently running in.
+     *
+     * <p>configArray represents the list of supported {@link VehicleGear}s for {@code
+     * CURRENT_GEAR}. For example, the configArray for an EV vehicle is set as follows:
+     *
+     * <ul>
+     *  <li>configArray[0] = {@link VehicleGear#GEAR_REVERSE}
+     *  <li>configArray[1] = {@link VehicleGear#GEAR_PARK}
+     *  <li>configArray[2] = {@link VehicleGear#GEAR_DRIVE}
+     * </ul>
+     *
+     * <p>Example automatic transmission configArray:
+     *
+     * <ul>
+     *  <li>configArray[0] = {@link VehicleGear#GEAR_NEUTRAL}
+     *  <li>configArray[1] = {@link VehicleGear#GEAR_REVERSE}
+     *  <li>configArray[2] = {@link VehicleGear#GEAR_PARK}
+     *  <li>configArray[4] = {@link VehicleGear#GEAR_FIRST}
+     *  <li>configArray[5] = {@link VehicleGear#GEAR_SECOND}
+     *  <li>...
+     * </ul>
+     *
+     * <p>Example manual transmission configArray:
+     *
+     * <ul>
+     *  <li>configArray[0] = {@link VehicleGear#GEAR_NEUTRAL}
+     *  <li>configArray[1] = {@link VehicleGear#GEAR_REVERSE}
+     *  <li>configArray[4] = {@link VehicleGear#GEAR_FIRST}
+     *  <li>configArray[5] = {@link VehicleGear#GEAR_SECOND}
+     *  <li>...
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
     @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int CURRENT_GEAR = 289408001;
@@ -393,7 +524,15 @@
     public static final int PARKING_BRAKE_ON = 287310850;
     /**
      * Auto-apply parking brake.
-     * Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
+     *  <li>{@code Boolean} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_POWERTRAIN}.
      */
     @RequiresPermission(Car.PERMISSION_POWERTRAIN)
     public static final int PARKING_BRAKE_AUTO_APPLY = 287310851;
@@ -730,7 +869,15 @@
     public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
     /**
      * Outside temperature in celsius.
-     * Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
+     *
+     * <ul>
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
+     *  <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
+     *  <li>{@link android.car.hardware.CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}
+     *  <li>{@code Float} property type
+     * </ul>
+     *
+     * <p>Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
      */
     @RequiresPermission(Car.PERMISSION_EXTERIOR_ENVIRONMENT)
     public static final int ENV_OUTSIDE_TEMPERATURE = 291505923;
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index dace5a8..f42da45 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -307,13 +307,20 @@
     public @interface UserIdentificationAssociationValue{}
 
     private final Object mLock = new Object();
+
     private final ICarUserService mService;
     private final UserManager mUserManager;
 
+    /**
+     * Map of listeners registers by the app.
+     */
     @Nullable
     @GuardedBy("mLock")
     private ArrayMap<UserLifecycleListener, Executor> mListeners;
 
+    /**
+     * Receiver used to receive user-lifecycle callbacks from the service.
+     */
     @Nullable
     @GuardedBy("mLock")
     private LifecycleResultReceiver mReceiver;
@@ -332,6 +339,7 @@
     public CarUserManager(@NonNull Car car, @NonNull ICarUserService service,
             @NonNull UserManager userManager) {
         super(car);
+
         mService = service;
         mUserManager = userManager;
     }
@@ -524,20 +532,31 @@
         Objects.requireNonNull(listener, "listener cannot be null");
 
         int uid = myUid();
+        String packageName = getContext().getPackageName();
+        if (DBG) {
+            Log.d(TAG, "addListener(): uid=" + uid + ", pkg=" + packageName
+                    + ", listener=" + listener);
+        }
         synchronized (mLock) {
             Preconditions.checkState(mListeners == null || !mListeners.containsKey(listener),
                     "already called for this listener");
             if (mReceiver == null) {
                 mReceiver = new LifecycleResultReceiver();
                 try {
-                    EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid);
-                    if (DBG) Log.d(TAG, "Setting lifecycle receiver for uid " + uid);
-                    mService.setLifecycleListenerForUid(mReceiver);
+                    EventLog.writeEvent(EventLogTags.CAR_USER_MGR_ADD_LISTENER, uid, packageName);
+                    if (DBG) {
+                        Log.d(TAG, "Setting lifecycle receiver for uid " + uid + " and package "
+                                + packageName);
+                    }
+                    mService.setLifecycleListenerForApp(packageName, mReceiver);
                 } catch (RemoteException e) {
                     handleRemoteExceptionFromCarService(e);
                 }
             } else {
-                if (DBG) Log.d(TAG, "Already set receiver for uid " + uid);
+                if (DBG) {
+                    Log.d(TAG, "Already set receiver for uid " + uid + " and package "
+                            + packageName);
+                }
             }
 
             if (mListeners == null) {
@@ -547,7 +566,7 @@
                         + " already has " + mListeners.size() + " listeners: "
                         + mListeners.keySet().stream()
                                 .map((l) -> getLambdaName(l))
-                                .collect(Collectors.toList()), new Exception());
+                                .collect(Collectors.toList()), new Exception("caller's stack"));
             }
             if (DBG) Log.d(TAG, "Adding listener: " + listener);
             mListeners.put(listener, executor);
@@ -568,6 +587,11 @@
         Objects.requireNonNull(listener, "listener cannot be null");
 
         int uid = myUid();
+        String packageName = getContext().getPackageName();
+        if (DBG) {
+            Log.d(TAG, "removeListener(): uid=" + uid + ", pkg=" + packageName
+                    + ", listener=" + listener);
+        }
         synchronized (mLock) {
             Preconditions.checkState(mListeners != null && mListeners.containsKey(listener),
                     "not called for this listener yet");
@@ -584,10 +608,13 @@
                 return;
             }
 
-            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid);
-            if (DBG) Log.d(TAG, "Removing lifecycle receiver for uid=" + uid);
+            EventLog.writeEvent(EventLogTags.CAR_USER_MGR_REMOVE_LISTENER, uid, packageName);
+            if (DBG) {
+                Log.d(TAG, "Removing lifecycle receiver for uid=" + uid + " and package "
+                        + packageName);
+            }
             try {
-                mService.resetLifecycleListenerForUid();
+                mService.resetLifecycleListenerForApp(mReceiver);
                 mReceiver = null;
             } catch (RemoteException e) {
                 handleRemoteExceptionFromCarService(e);
diff --git a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
index 65a3fb1..45fdfe9 100644
--- a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
+++ b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
@@ -69,8 +69,8 @@
 150100 car_user_svc_initial_user_info_req (request_type|1),(timeout|1)
 150101 car_user_svc_initial_user_info_resp (status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
 150103 car_user_svc_set_initial_user (user_id|1)
-150104 car_user_svc_set_lifecycle_listener (uid|1)
-150105 car_user_svc_reset_lifecycle_listener (uid|1)
+150104 car_user_svc_set_lifecycle_listener (uid|1),(package_name|3)
+150105 car_user_svc_reset_lifecycle_listener (uid|1),(package_name|3)
 150106 car_user_svc_switch_user_req (user_id|1),(timeout|1)
 150107 car_user_svc_switch_user_resp (hal_callback_status|1),(user_switch_status|1),(error_message|3)
 150108 car_user_svc_post_switch_user_req (target_user_id|1),(current_user_id|1)
@@ -86,7 +86,7 @@
 150118 car_user_svc_create_user_user_removed (user_id|1),(reason|3)
 150119 car_user_svc_remove_user_req (user_id|1),(hasCallerRestrictions|1)
 150120 car_user_svc_remove_user_resp (user_id|1),(result|1)
-150121 car_user_svc_notify_app_lifecycle_listener (uid|1),(event_type|1),(from_user_id|1),(to_user_id|1)
+150121 car_user_svc_notify_app_lifecycle_listener (uid|1),(package_name|3),(event_type|1),(from_user_id|1),(to_user_id|1)
 150122 car_user_svc_notify_internal_lifecycle_listener (listener_name|3),(event_type|1),(from_user_id|1),(to_user_id|1)
 150123 car_user_svc_pre_creation_requested (number_users|1),(number_guests|1)
 150124 car_user_svc_pre_creation_status (number_existing_users|1),(number_users_to_add|1),(number_users_to_remove|1),(number_existing_guests|1),(number_guests_to_add|1),(number_guests_to_remove|1),(number_invalid_users_to_remove|1)
@@ -111,8 +111,8 @@
 150152 car_user_hal_create_user_resp (request_id|1),(status|1),(result|1),(error_message|3)
 150153 car_user_hal_remove_user_req (target_user_id|1),(current_user_id|1)
 
-150171 car_user_mgr_add_listener (uid|1)
-150172 car_user_mgr_remove_listener (uid|1)
+150171 car_user_mgr_add_listener (uid|1),(package_name|3)
+150172 car_user_mgr_remove_listener (uid|1),(package_name|3)
 150173 car_user_mgr_disconnected (uid|1)
 150174 car_user_mgr_switch_user_req (uid|1),(user_id|1)
 150175 car_user_mgr_switch_user_resp (uid|1),(status|1),(error_message|3)
diff --git a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
index 627aa86..3693ebc 100644
--- a/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
+++ b/car-test-lib/src/android/car/testapi/BlockingUserLifecycleListener.java
@@ -54,6 +54,8 @@
 
     private static final long DEFAULT_TIMEOUT_MS = 2_000;
 
+    private static int sNextId;
+
     private final Object mLock = new Object();
 
     private final CountDownLatch mLatch = new CountDownLatch(1);
@@ -79,6 +81,8 @@
 
     private final long mTimeoutMs;
 
+    private final int mId = ++sNextId;
+
     private BlockingUserLifecycleListener(Builder builder) {
         mExpectedEventTypes = Collections
                 .unmodifiableList(new ArrayList<>(builder.mExpectedEventTypes));
@@ -276,7 +280,7 @@
     @NonNull
     private String stateToString() {
         synchronized (mLock) {
-            return "timeout=" + mTimeoutMs + "ms"
+            return "id=" + mId + ",timeout=" + mTimeoutMs + "ms"
                     + ",expectedEventTypes=" + toString(mExpectedEventTypes)
                     + ",expectedEventTypesLeft=" + toString(mExpectedEventTypesLeft)
                     + (expectingSpecificUser() ? ",forUser=" + mForUserId : "")
diff --git a/car_product/car_ui_portrait/Android.mk b/car_product/car_ui_portrait/Android.mk
new file mode 100644
index 0000000..c75d51a
--- /dev/null
+++ b/car_product/car_ui_portrait/Android.mk
@@ -0,0 +1,20 @@
+# Copyright (C) 2021 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.
+#
+
+car_ui_portrait_modules := \
+    rro/car-ui-customizations \
+    apps/HideApps
+
+include $(call all-named-subdir-makefiles,$(car_ui_portrait_modules))
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/Android.bp b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/Android.bp
new file mode 100644
index 0000000..3c5fb85
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2021 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+    name: "CarUiPortraitSettings",
+    overrides: ["CarSettings"],
+    platform_apis: true,
+
+    manifest: "AndroidManifest.xml",
+
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "CarSettings-core",
+    ],
+
+    certificate: "platform",
+
+    optimize: {
+        enabled: false,
+    },
+
+    privileged: true,
+
+    dex_preopt: {
+        enabled: false,
+    },
+
+    required: ["allowed_privapp_com.android.car.settings"],
+
+    dxflags: ["--multi-dex"],
+
+    product_variables: {
+        pdk: {
+            enabled: false,
+        },
+    },
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
new file mode 100644
index 0000000..82fcdf5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.settings"
+          android:sharedUserId="android.uid.system"
+          coreApp="true">
+</manifest>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/settings_recyclerview_default.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/settings_recyclerview_default.xml
new file mode 100644
index 0000000..4616fdf
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/settings_recyclerview_default.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.android.car.ui.FocusArea
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/settings_car_ui_focus_area"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <com.android.car.ui.recyclerview.CarUiRecyclerView
+            android:id="@+id/settings_recycler_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:tag="carUiPreferenceRecyclerView"
+            app:carUiSize="small"
+            app:enableDivider="true" />
+    </com.android.car.ui.FocusArea>
+</merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/top_level_recyclerview.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/top_level_recyclerview.xml
new file mode 100644
index 0000000..4dbe9be
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/layout/top_level_recyclerview.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.android.car.ui.FocusArea
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/settings_car_ui_focus_area"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <com.android.car.ui.recyclerview.CarUiRecyclerView
+            android:id="@+id/top_level_recycler_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:tag="carUiPreferenceRecyclerView"
+            app:carUiSize="small"
+            app:enableDivider="true" />
+    </com.android.car.ui.FocusArea>
+</merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/config.xml
new file mode 100644
index 0000000..eaf603f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <bool name="config_global_force_single_pane">false</bool>
+    <string name="config_homepage_fragment_class" translatable="false">com.android.car.settings.bluetooth.BluetoothSettingsFragment</string>
+    <bool name="config_top_level_enable_chevrons">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/dimens.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/dimens.xml
new file mode 100644
index 0000000..f2a58a4
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSettings/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2018 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.
+-->
+
+<resources>
+    <!-- Top-level menu -->
+    <dimen name="top_level_menu_width">400dp</dimen>
+    <dimen name="top_level_recyclerview_margin_right">@*android:dimen/car_padding_2</dimen>
+    <dimen name="top_level_foreground_icon_inset">8dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
new file mode 100644
index 0000000..c195412
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/Android.bp
@@ -0,0 +1,73 @@
+// Copyright (C) 2021 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.
+
+android_app {
+    name: "CarUiPortraitSystemUI",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "CarSystemUI-core",
+    ],
+
+    libs: [
+        "android.car",
+    ],
+
+    manifest: "AndroidManifest.xml",
+
+    overrides: [
+        "CarSystemUI",
+    ],
+
+    platform_apis: true,
+    system_ext_specific: true,
+    certificate: "platform",
+    privileged: true,
+
+    optimize: {
+        proguard_flags_files: [
+            "proguard.flags",
+        ],
+    },
+    dxflags: ["--multi-dex"],
+
+    plugins: ["dagger2-compiler"],
+
+    required: ["privapp_whitelist_com.android.systemui", "allowed_privapp_com.android.carsystemui"],
+}
+
+//####################################################################################
+// Build a static library to help mocking in testing. This is meant to be used
+// for internal unit tests.
+//####################################################################################
+android_library {
+    name: "CarUiPortraitSystemUI-tests",
+
+    srcs: ["src/**/*.java"],
+
+    resource_dirs: ["res"],
+
+    libs: [
+        "android.car",
+    ],
+
+    static_libs: [
+        "CarSystemUI-tests",
+    ],
+
+    plugins: ["dagger2-compiler"],
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
new file mode 100644
index 0000000..fc2e241
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          package="com.android.systemui"
+          android:sharedUserId="android.uid.systemui"
+          coreApp="true">
+</manifest>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
new file mode 100644
index 0000000..3de0064
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/proguard.flags
@@ -0,0 +1,6 @@
+-keep class com.android.systemui.CarUiPortraitSystemUIFactory
+
+-keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent { *; }
+-keep class com.android.systemui.DaggerCarUiPortraitGlobalRootComponent$CarUiPortraitSysUIComponentImpl { *; }
+
+-include ../../../../../../../packages/apps/Car/SystemUI/proguard.flags
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_apps.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_apps.xml
new file mode 100644
index 0000000..a98b3a7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_apps.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M6,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM16,6c0,1.1 0.9,2 2,2s2,-0.9 2,-2 -0.9,-2 -2,-2 -2,0.9 -2,2zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_hvac.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_hvac.xml
new file mode 100644
index 0000000..b42c86c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_hvac.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24"
+                android:viewportHeight="24">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_mic.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_mic.xml
new file mode 100644
index 0000000..f282b65
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_mic.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M12,14c1.66,0 3,-1.34 3,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,5zM17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5L5,11c0,3.53 2.61,6.43 6,6.92L11,21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92h-2z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_notification.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_notification.xml
new file mode 100644
index 0000000..27b69a8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_notification.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <vector android:width="@dimen/system_bar_icon_drawing_size"
+                android:height="@dimen/system_bar_icon_drawing_size"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0">
+            <path
+                android:fillColor="@color/car_nav_icon_fill_color"
+                android:pathData="M18,17v-6c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v6L4,17v2h16v-2h-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6zM12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2z"/>
+        </vector>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
new file mode 100644
index 0000000..45887dc
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/car_ic_user_icon.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/system_bar_user_icon_drawing_size"
+    android:height="@dimen/system_bar_user_icon_drawing_size"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="@color/system_bar_icon_color"
+      android:pathData="M12,5.9c1.16,0 2.1,0.94 2.1,2.1s-0.94,2.1 -2.1,2.1S9.9,9.16 9.9,8s0.94,-2.1 2.1,-2.1m0,9c2.97,0 6.1,1.46 6.1,2.1v1.1L5.9,18.1L5.9,17c0,-0.64 3.13,-2.1 6.1,-2.1M12,4C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,13c-2.67,0 -8,1.34 -8,4v3h16v-3c0,-2.66 -5.33,-4 -8,-4z"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml
new file mode 100644
index 0000000..cac886c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/exit_icon_background.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <size android:width="@dimen/rear_view_camera_exit_button_width"
+                  android:height="@dimen/rear_view_camera_exit_button_height"/>
+            <solid android:color="@color/rear_view_camera_button_background"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape android:shape="oval">
+                    <solid android:color="?android:colorAccent"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar.xml
new file mode 100644
index 0000000..7e72373
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:id="@android:id/background">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/hvac_off_background_color" />
+        </shape>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape android:shape="rectangle">
+                <solid android:color="@color/hvac_on_background_color" />
+            </shape>
+        </clip>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_background.xml
new file mode 100644
index 0000000..d6efa1b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_background.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+            <solid android:color="@color/hvac_off_background_color" />
+        </shape>
+    </item>
+    <item
+        android:gravity="left"
+        android:width="@dimen/hvac_panel_button_dimen">
+        <selector>
+            <item android:state_selected="true">
+                <shape android:shape="rectangle">
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                    <solid android:color="@color/hvac_on_background_color" />
+                </shape>
+            </item>
+            <item>
+                <shape android:shape="rectangle">
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                    <solid android:color="@color/hvac_off_background_color" />
+                </shape>
+            </item>
+        </selector>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb.xml
new file mode 100644
index 0000000..63b731f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_1.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_1.xml
new file mode 100644
index 0000000..a0befd8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_1.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_1"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_2.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_2.xml
new file mode 100644
index 0000000..c0725c3
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_2.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_2"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_3.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_3.xml
new file mode 100644
index 0000000..d11d90b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_3.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_3"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_4.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_4.xml
new file mode 100644
index 0000000..177d9a4
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_4.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_4"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_5.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_5.xml
new file mode 100644
index 0000000..c87f92a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_5.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_5"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_6.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_6.xml
new file mode 100644
index 0000000..fc8452d
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_6.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_6"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_7.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_7.xml
new file mode 100644
index 0000000..4531e65
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_7.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_7"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_8.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_8.xml
new file mode 100644
index 0000000..9905a24
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_8.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_on_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_8"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_off.xml
new file mode 100644
index 0000000..b6c1cb9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/fan_speed_seek_bar_thumb_off.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="@color/hvac_off_background_color"/>
+            <size android:height="@dimen/hvac_panel_button_dimen"
+                  android:width="@dimen/hvac_panel_button_dimen"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_mode_fan_off"
+        android:gravity="center"
+        android:width="@dimen/hvac_panel_icon_dimen"
+        android:height="@dimen/hvac_panel_icon_dimen"/>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_cool_on_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_cool_on_bg.xml
new file mode 100644
index 0000000..711158c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_cool_on_bg.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <solid android:color="@color/hvac_on_cooling_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_heat_on_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_heat_on_bg.xml
new file mode 100644
index 0000000..d069bd9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_heat_on_bg.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <solid android:color="@color/hvac_on_heating_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_off_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_off_bg.xml
new file mode 100644
index 0000000..2cc9886
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_off_bg.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape xmlns:android="http://schemas.android.com/apk/res/android">
+            <solid android:color="@color/hvac_off_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_off_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_off_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_on_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_on_bg.xml
new file mode 100644
index 0000000..a5d66bc
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_button_on_bg.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape>
+            <solid android:color="@color/hvac_on_background_color"/>
+            <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="@color/car_ui_ripple_color">
+            <item android:id="@android:id/mask">
+                <shape>
+                    <solid android:color="?android:colorAccent"/>
+                    <corners android:radius="@dimen/hvac_panel_on_button_radius"/>
+                </shape>
+            </item>
+        </ripple>
+    </item>
+</layer-list>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_cool_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_cool_background.xml
new file mode 100644
index 0000000..b1f9e79
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_cool_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:drawable="@drawable/hvac_button_cool_on_bg"/>
+    <item android:drawable="@drawable/hvac_button_off_bg"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_default_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_default_background.xml
new file mode 100644
index 0000000..84f502b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_default_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:drawable="@drawable/hvac_button_on_bg"/>
+    <item android:drawable="@drawable/hvac_button_off_bg"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_heat_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_heat_background.xml
new file mode 100644
index 0000000..09d091e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_heat_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:drawable="@drawable/hvac_button_heat_on_bg"/>
+    <item android:drawable="@drawable/hvac_button_off_bg"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
new file mode 100644
index 0000000..1bdac16
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/hvac_panel_bg.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/hvac_background_color"/>
+    <corners android:radius="@dimen/hvac_panel_bg_radius"/>
+</shape>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_off.xml
new file mode 100644
index 0000000..5458c73
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_off.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M42.0001,22H35.6601L40.7401,16.92C41.5201,16.14 41.5201,14.88 40.7401,14.1C39.9601,13.32 38.6801,13.32 37.9001,14.1L30.0001,22H26.0001V18L33.9001,10.1C34.6801,9.32 34.6801,8.04 33.9001,7.26C33.1201,6.48 31.8601,6.48 31.0801,7.26L26.0001,12.34V6C26.0001,4.9 25.1001,4 24.0001,4C22.9001,4 22.0001,4.9 22.0001,6V12.34L16.9201,7.26C16.1401,6.48 14.8801,6.48 14.1001,7.26C13.3201,8.04 13.3201,9.32 14.1001,10.1L22.0001,18V20.34L27.6601,26H30.0001L37.9001,33.9C38.6801,34.68 39.9601,34.68 40.7401,33.9C41.5201,33.12 41.5201,31.86 40.7401,31.08L35.6601,26H42.0001C43.1001,26 44.0001,25.1 44.0001,24C44.0001,22.9 43.1001,22 42.0001,22Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M1.5801,11.24L12.3401,22H6.0001C4.9001,22 4.0001,22.9 4.0001,24C4.0001,25.1 4.9001,26 6.0001,26H12.3401L7.2601,31.08C6.4801,31.86 6.4801,33.12 7.2601,33.9C8.0401,34.68 9.3201,34.68 10.1001,33.9L17.1801,26.82L21.1801,30.82L14.1001,37.9C13.3201,38.68 13.3201,39.96 14.1001,40.74C14.8801,41.52 16.1401,41.52 16.9201,40.74L22.0001,35.66V42C22.0001,43.1 22.9001,44 24.0001,44C25.1001,44 26.0001,43.1 26.0001,42V35.66L38.3401,48L41.1601,45.18L4.4001,8.4L1.5801,11.24Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_on.xml
new file mode 100644
index 0000000..f86563e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_ac_on.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M42,22H35.66L40.74,16.92C41.52,16.14 41.52,14.88 40.74,14.1C39.96,13.32 38.68,13.32 37.9,14.1L30,22H26V18L33.9,10.1C34.68,9.32 34.68,8.04 33.9,7.26C33.12,6.48 31.86,6.48 31.08,7.26L26,12.34V6C26,4.9 25.1,4 24,4C22.9,4 22,4.9 22,6V12.34L16.92,7.26C16.14,6.48 14.88,6.48 14.1,7.26C13.32,8.04 13.32,9.32 14.1,10.1L22,18V22H18L10.1,14.1C9.32,13.32 8.04,13.32 7.26,14.1C6.48,14.88 6.48,16.14 7.26,16.92L12.34,22H6C4.9,22 4,22.9 4,24C4,25.1 4.9,26 6,26H12.34L7.26,31.08C6.48,31.86 6.48,33.12 7.26,33.9C8.04,34.68 9.32,34.68 10.1,33.9L18,26H22V30L14.1,37.9C13.32,38.68 13.32,39.96 14.1,40.74C14.88,41.52 16.14,41.52 16.92,40.74L22,35.66V42C22,43.1 22.9,44 24,44C25.1,44 26,43.1 26,42V35.66L31.08,40.74C31.86,41.52 33.12,41.52 33.9,40.74C34.68,39.96 34.68,38.68 33.9,37.9L26,30V26H30L37.9,33.9C38.68,34.68 39.96,34.68 40.74,33.9C41.52,33.12 41.52,31.86 40.74,31.08L35.66,26H42C43.1,26 44,25.1 44,24C44,22.9 43.1,22 42,22Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42,22H35.66L40.74,16.92C41.52,16.14 41.52,14.88 40.74,14.1C39.96,13.32 38.68,13.32 37.9,14.1L30,22H26V18L33.9,10.1C34.68,9.32 34.68,8.04 33.9,7.26C33.12,6.48 31.86,6.48 31.08,7.26L26,12.34V6C26,4.9 25.1,4 24,4C22.9,4 22,4.9 22,6V12.34L16.92,7.26C16.14,6.48 14.88,6.48 14.1,7.26C13.32,8.04 13.32,9.32 14.1,10.1L22,18V22H18L10.1,14.1C9.32,13.32 8.04,13.32 7.26,14.1C6.48,14.88 6.48,16.14 7.26,16.92L12.34,22H6C4.9,22 4,22.9 4,24C4,25.1 4.9,26 6,26H12.34L7.26,31.08C6.48,31.86 6.48,33.12 7.26,33.9C8.04,34.68 9.32,34.68 10.1,33.9L18,26H22V30L14.1,37.9C13.32,38.68 13.32,39.96 14.1,40.74C14.88,41.52 16.14,41.52 16.92,40.74L22,35.66V42C22,43.1 22.9,44 24,44C25.1,44 26,43.1 26,42V35.66L31.08,40.74C31.86,41.52 33.12,41.52 33.9,40.74C34.68,39.96 34.68,38.68 33.9,37.9L26,30V26H30L37.9,33.9C38.68,34.68 39.96,34.68 40.74,33.9C41.52,33.12 41.52,31.86 40.74,31.08L35.66,26H42C43.1,26 44,25.1 44,24C44,22.9 43.1,22 42,22Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_off.xml
new file mode 100644
index 0000000..3cf394e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_off.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M40.209,16.7912L38.789,15.3812L36.999,17.1712L36.999,3.0012L34.999,3.0012L34.999,17.1712L33.209,15.3812L31.789,16.7912L35.999,21.0012L40.209,16.7912Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_on.xml
new file mode 100644
index 0000000..a4c1eb2
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_feet_on.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M40.209,16.7912L38.789,15.3812L36.999,17.1712L36.999,3.0012L34.999,3.0012L34.999,17.1712L33.209,15.3812L31.789,16.7912L35.999,21.0012L40.209,16.7912Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_off.xml
new file mode 100644
index 0000000..981958a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_off.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M40.79,7.79L39.38,9.21L41.17,11H27V13H41.17L39.38,14.79L40.79,16.21L45,12L40.79,7.79Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M34.0357,32.7879L24.8843,46.6596C24.5051,47.2343 24.9173,48 25.6058,48C27.1439,48 28.6243,47.4142 29.746,46.3617L39.1144,37.5709C40.9682,35.8313 43.4149,34.8632 45.9571,34.8632H54.2339C56.5366,34.8632 58.6362,33.5453 59.6372,31.4715L66.7184,16.8024C67.3115,15.5736 66.4162,14.1474 65.0518,14.1474C64.0756,14.1474 63.157,14.6096 62.5752,15.3935L55.9986,24.2545C54.1122,26.7962 51.1338,28.2947 47.9686,28.2947H42.3829C39.0223,28.2947 35.8864,29.9828 34.0357,32.7879Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M62.0005,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_on.xml
new file mode 100644
index 0000000..4dc3272
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_head_on.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M40.79,7.79L39.38,9.21L41.17,11H27V13H41.17L39.38,14.79L40.79,16.21L45,12L40.79,7.79Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M34.0357,32.7879L24.8843,46.6596C24.5051,47.2343 24.9173,48 25.6058,48C27.1439,48 28.6243,47.4142 29.746,46.3617L39.1144,37.5709C40.9682,35.8313 43.4149,34.8632 45.9571,34.8632H54.2339C56.5366,34.8632 58.6362,33.5453 59.6372,31.4715L66.7184,16.8024C67.3115,15.5736 66.4162,14.1474 65.0518,14.1474C64.0756,14.1474 63.157,14.6096 62.5752,15.3935L55.9986,24.2545C54.1122,26.7962 51.1338,28.2947 47.9686,28.2947H42.3829C39.0223,28.2947 35.8864,29.9828 34.0357,32.7879Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M62.0005,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_off.xml
new file mode 100644
index 0000000..2cdfa90
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_off.xml
@@ -0,0 +1,53 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M41.5603,10.0488C37.5686,12.8863 45.4033,16.6289 41.5603,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M37.0374,10.0488C33.0456,12.8863 40.8804,16.6289 37.0374,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M32.5135,10.0488C28.5217,12.8863 36.3565,16.629 32.5135,19.0973"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M28.8859,15.7037H27.804L25.0881,6.2391C24.7768,5.1544 25.3126,4.0062 26.3439,3.5479C30.1667,1.8493 33.7188,1 37,1C40.2812,1 43.8333,1.8493 47.6561,3.5479C48.6874,4.0061 49.2232,5.1544 48.9119,6.2391L46.196,15.7037H45.1141"
+      android:strokeLineJoin="round"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_on.xml
new file mode 100644
index 0000000..a3510b1
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_airflow_windshield_on.xml
@@ -0,0 +1,53 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="49">
+  <path
+      android:pathData="M34.0338,32.7879L24.8823,46.6596C24.5032,47.2343 24.9153,48 25.6038,48C27.1419,48 28.6223,47.4142 29.744,46.3617L39.1124,37.5709C40.9662,35.8313 43.413,34.8632 45.9551,34.8632H54.2319C56.5346,34.8632 58.6342,33.5453 59.6353,31.4715L66.7164,16.8024C67.3096,15.5736 66.4143,14.1474 65.0499,14.1474C64.0736,14.1474 63.155,14.6096 62.5732,15.3935L55.9967,24.2545C54.1102,26.7962 51.1319,28.2947 47.9666,28.2947H42.3809C39.0203,28.2947 35.8844,29.9828 34.0338,32.7879Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M61.9985,5.0526a5,5.0526 0,1 0,10 0a5,5.0526 0,1 0,-10 0z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M41.5603,10.0488C37.5686,12.8863 45.4033,16.6289 41.5603,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M37.0374,10.0488C33.0456,12.8863 40.8804,16.6289 37.0374,19.0972"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M32.5135,10.0488C28.5217,12.8863 36.3565,16.629 32.5135,19.0973"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M28.8859,15.7037H27.804L25.0881,6.2391C24.7768,5.1544 25.3126,4.0062 26.3439,3.5479C30.1667,1.8493 33.7188,1 37,1C40.2812,1 43.8333,1.8493 47.6561,3.5479C48.6874,4.0061 49.2232,5.1544 48.9119,6.2391L46.196,15.7037H45.1141"
+      android:strokeLineJoin="round"
+      android:strokeWidth="2"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_off.xml
new file mode 100644
index 0000000..65a4b12
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_off.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M0.2653,30L4.6853,17.828H7.3203L11.7573,30H9.2243L8.2383,27.093H3.7843L2.7983,30H0.2653ZM5.5183,21.942L4.4983,24.985H7.5243L6.5043,21.942L6.0793,20.48H5.9433L5.5183,21.942ZM17.9681,30.272C16.4721,30.272 15.2934,29.8243 14.4321,28.929C13.5821,28.0337 13.1571,26.7927 13.1571,25.206V17.828H15.4181V25.359C15.4181,26.2203 15.6334,26.8947 16.0641,27.382C16.4947,27.858 17.1294,28.096 17.9681,28.096C18.8067,28.096 19.4357,27.858 19.8551,27.382C20.2857,26.8947 20.5011,26.2203 20.5011,25.359V17.828H22.7621V25.206C22.7621,26.226 22.5694,27.1157 22.1841,27.875C21.7987,28.6343 21.2491,29.2237 20.5351,29.643C19.8211,30.0623 18.9654,30.272 17.9681,30.272ZM28.299,30V20.004H24.559V17.828H34.317V20.004H30.577V30H28.299ZM41.1274,30.272C39.926,30.272 38.8834,30 37.9994,29.456C37.1154,28.9007 36.4297,28.147 35.9424,27.195C35.455,26.2317 35.2114,25.138 35.2114,23.914C35.2114,22.6787 35.455,21.585 35.9424,20.633C36.4297,19.681 37.1154,18.933 37.9994,18.389C38.8834,17.8337 39.926,17.556 41.1274,17.556C42.3287,17.556 43.3714,17.8337 44.2554,18.389C45.1394,18.933 45.825,19.681 46.3124,20.633C46.7997,21.585 47.0434,22.6787 47.0434,23.914C47.0434,25.138 46.7997,26.2317 46.3124,27.195C45.825,28.147 45.1394,28.9007 44.2554,29.456C43.3714,30 42.3287,30.272 41.1274,30.272ZM41.1274,28.096C42.204,28.096 43.071,27.7333 43.7284,27.008C44.397,26.2827 44.7314,25.2513 44.7314,23.914C44.7314,22.5767 44.397,21.5453 43.7284,20.82C43.071,20.0947 42.204,19.732 41.1274,19.732C40.0507,19.732 39.178,20.0947 38.5094,20.82C37.852,21.5453 37.5234,22.5767 37.5234,23.914C37.5234,25.2513 37.852,26.2827 38.5094,27.008C39.178,27.7333 40.0507,28.096 41.1274,28.096Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_on.xml
new file mode 100644
index 0000000..c847a95
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_auto_on.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M0.2653,30L4.6853,17.828H7.3203L11.7573,30H9.2243L8.2383,27.093H3.7843L2.7983,30H0.2653ZM5.5183,21.942L4.4983,24.985H7.5243L6.5043,21.942L6.0793,20.48H5.9433L5.5183,21.942ZM17.9681,30.272C16.4721,30.272 15.2934,29.8243 14.4321,28.929C13.5821,28.0337 13.1571,26.7927 13.1571,25.206V17.828H15.4181V25.359C15.4181,26.2203 15.6334,26.8947 16.0641,27.382C16.4947,27.858 17.1294,28.096 17.9681,28.096C18.8067,28.096 19.4357,27.858 19.8551,27.382C20.2857,26.8947 20.5011,26.2203 20.5011,25.359V17.828H22.7621V25.206C22.7621,26.226 22.5694,27.1157 22.1841,27.875C21.7987,28.6343 21.2491,29.2237 20.5351,29.643C19.8211,30.0623 18.9654,30.272 17.9681,30.272ZM28.299,30V20.004H24.559V17.828H34.317V20.004H30.577V30H28.299ZM41.1274,30.272C39.926,30.272 38.8834,30 37.9994,29.456C37.1154,28.9007 36.4297,28.147 35.9424,27.195C35.455,26.2317 35.2114,25.138 35.2114,23.914C35.2114,22.6787 35.455,21.585 35.9424,20.633C36.4297,19.681 37.1154,18.933 37.9994,18.389C38.8834,17.8337 39.926,17.556 41.1274,17.556C42.3287,17.556 43.3714,17.8337 44.2554,18.389C45.1394,18.933 45.825,19.681 46.3124,20.633C46.7997,21.585 47.0434,22.6787 47.0434,23.914C47.0434,25.138 46.7997,26.2317 46.3124,27.195C45.825,28.147 45.1394,28.9007 44.2554,29.456C43.3714,30 42.3287,30.272 41.1274,30.272ZM41.1274,28.096C42.204,28.096 43.071,27.7333 43.7284,27.008C44.397,26.2827 44.7314,25.2513 44.7314,23.914C44.7314,22.5767 44.397,21.5453 43.7284,20.82C43.071,20.0947 42.204,19.732 41.1274,19.732C40.0507,19.732 39.178,20.0947 38.5094,20.82C37.852,21.5453 37.5234,22.5767 37.5234,23.914C37.5234,25.2513 37.852,26.2827 38.5094,27.008C39.178,27.7333 40.0507,28.096 41.1274,28.096Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml
new file mode 100644
index 0000000..4df0f11
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_close.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/rear_view_camera_exit_icon_width"
+        android:height="@dimen/rear_view_camera_exit_icon_height"
+        android:viewportWidth="26"
+        android:viewportHeight="26">
+    <path
+        android:pathData="M25.8327 2.75199L23.2477 0.166992L12.9994 10.4153L2.75102 0.166992L0.166016 2.75199L10.4144 13.0003L0.166016 23.2487L2.75102 25.8337L12.9994 15.5853L23.2477 25.8337L25.8327 23.2487L15.5844 13.0003L25.8327 2.75199Z"
+        android:fillColor="@color/rear_view_camera_exit_icon_color" />
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_off.xml
new file mode 100644
index 0000000..29bae07
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_off.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M55.4836,23.5C49.4334,27.8006 61.3082,33.4732 55.4836,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M48.6281,23.5C42.5779,27.8006 54.4527,33.4732 48.6281,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M41.7707,23.5C35.7205,27.8006 47.5953,33.4732 41.7707,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M36,32.5H32C30.8954,32.5 30,31.6046 30,30.5V13C30,11.8954 30.8954,11 32,11H64.5C65.6046,11 66.5,11.8954 66.5,13V30.5C66.5,31.6046 65.6046,32.5 64.5,32.5H62"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_on.xml
new file mode 100644
index 0000000..ca35897
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_rear_on.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M55.4836,23.5C49.4334,27.8006 61.3082,33.4732 55.4836,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M48.6281,23.5C42.5779,27.8006 54.4527,33.4732 48.6281,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M41.7707,23.5C35.7205,27.8006 47.5953,33.4732 41.7707,37.2143"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M36,32.5H32C30.8954,32.5 30,31.6046 30,30.5V13C30,11.8954 30.8954,11 32,11H64.5C65.6046,11 66.5,11.8954 66.5,13V30.5C66.5,31.6046 65.6046,32.5 64.5,32.5H62"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_off.xml
new file mode 100644
index 0000000..99a55de
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_off.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M54.1007,23.7148C48.0506,28.0154 59.9254,33.6881 54.1007,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M47.2453,23.7148C41.1951,28.0154 53.0699,33.6881 47.2453,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M40.3878,23.7148C34.3377,28.0154 46.2125,33.6881 40.3878,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M34.8897,32.2857H33.2499L29.1335,17.9407C28.6618,16.2966 29.4739,14.5563 31.0369,13.8618C36.831,11.2873 42.2146,10 47.1878,10C52.161,10 57.5447,11.2873 63.3387,13.8618C64.9018,14.5563 65.7139,16.2966 65.2421,17.9406L61.1257,32.2857H59.486"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_on.xml
new file mode 100644
index 0000000..9728826
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_defroster_windshield_on.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_wide_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="96"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M54.1007,23.7148C48.0506,28.0154 59.9254,33.6881 54.1007,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M47.2453,23.7148C41.1951,28.0154 53.0699,33.6881 47.2453,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M40.3878,23.7148C34.3377,28.0154 46.2125,33.6881 40.3878,37.4291"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M34.8897,32.2857H33.2499L29.1335,17.9407C28.6618,16.2966 29.4739,14.5563 31.0369,13.8618C36.831,11.2873 42.2146,10 47.1878,10C52.161,10 57.5447,11.2873 63.3387,13.8618C64.9018,14.5563 65.7139,16.2966 65.2421,17.9406L61.1257,32.2857H59.486"
+      android:strokeLineJoin="round"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_high.xml
new file mode 100644
index 0000000..afc41fd
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_high.xml
@@ -0,0 +1,40 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_low.xml
new file mode 100644
index 0000000..2888403
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_low.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_med.xml
new file mode 100644
index 0000000..98c5042
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_med.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_off.xml
new file mode 100644
index 0000000..5453dd5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_cool_off.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M9.708,0H11.522C12.022,0 12.5,0.177 12.854,0.492C14.146,1.646 14.324,3.461 13.276,4.797L12.949,5.213C11.271,7.354 11.081,10.155 12.459,12.461L17.528,20.946C19.855,24.842 19.399,29.596 16.362,33.081L12.495,37.52C12.136,37.932 11.404,37.79 11.268,37.284L4.898,13.59C3.834,9.63 4.369,5.463 6.408,1.821C7.033,0.705 8.311,0 9.708,0Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M25.871,36.811H38.065C41.142,36.811 43.636,39.037 43.636,41.784V43.027C43.636,45.773 41.142,48 38.065,48H22.607C20.021,48 17.542,47.083 15.714,45.451L14.161,44.065C13.552,43.521 13.636,42.62 14.336,42.174L20.205,38.432C21.858,37.378 23.839,36.811 25.871,36.811Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M39.701,13.057L37.221,13.945C37.026,13.804 36.809,13.674 36.592,13.577C36.777,12.677 37.275,11.865 38.066,11.345C40.254,9.893 39.528,6.167 36.506,6.167C31.75,6.167 29.757,9.427 31.056,12.298L31.945,14.779C31.804,14.974 31.674,15.191 31.576,15.408C30.677,15.223 29.865,14.725 29.345,13.934C27.893,11.746 24.167,12.472 24.167,15.494C24.167,20.261 27.427,22.254 30.298,20.943L32.779,20.055C32.974,20.196 33.191,20.326 33.407,20.423C33.223,21.323 32.725,22.135 31.934,22.655C29.746,24.107 30.472,27.833 33.494,27.833C38.261,27.833 40.254,24.573 38.943,21.702L38.055,19.221C38.196,19.026 38.326,18.809 38.423,18.593C39.322,18.777 40.135,19.275 40.655,20.066C42.106,22.243 45.822,21.517 45.822,18.495C45.833,13.75 42.572,11.757 39.701,13.057ZM35,18.625C34.101,18.625 33.375,17.899 33.375,17C33.375,16.101 34.101,15.375 35,15.375C35.899,15.375 36.625,16.101 36.625,17C36.625,17.899 35.899,18.625 35,18.625Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_high.xml
new file mode 100644
index 0000000..326b9b9
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_high.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_low.xml
new file mode 100644
index 0000000..0528b68
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_low.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_med.xml
new file mode 100644
index 0000000..326ec7f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_med.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_off.xml
new file mode 100644
index 0000000..78d0236
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_driver_seat_heat_off.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M11.522,0H9.708C8.311,0 7.033,0.705 6.408,1.821C4.369,5.463 3.834,9.63 4.898,13.59L11.268,37.284C11.404,37.79 12.136,37.932 12.495,37.52L16.362,33.081C19.399,29.596 19.855,24.842 17.528,20.946L12.459,12.461C11.081,10.155 11.271,7.354 12.949,5.213L13.276,4.797C14.324,3.461 14.146,1.646 12.854,0.492C12.5,0.177 12.022,0 11.522,0ZM38.065,36.811H25.871C23.839,36.811 21.858,37.378 20.205,38.432L14.336,42.174C13.636,42.62 13.552,43.521 14.161,44.065L15.714,45.451C17.542,47.083 20.021,48 22.607,48H38.065C41.142,48 43.636,45.773 43.636,43.027V41.784C43.636,39.037 41.142,36.811 38.065,36.811ZM39.06,13.841C38.405,14.32 38.089,14.748 37.933,15.092C37.782,15.428 37.739,15.787 37.799,16.216C37.933,17.181 38.537,18.271 39.372,19.674L39.506,19.899C40.228,21.107 41.121,22.603 41.377,24.089C41.525,24.942 41.481,25.861 41.069,26.767C40.66,27.663 39.952,28.411 39.001,29.04C38.31,29.497 37.38,29.307 36.923,28.616C36.466,27.925 36.656,26.994 37.347,26.537C37.96,26.132 38.221,25.78 38.339,25.523C38.451,25.276 38.488,24.99 38.421,24.599C38.265,23.692 37.648,22.643 36.794,21.209L36.775,21.176C36.019,19.906 35.059,18.293 34.827,16.63C34.703,15.738 34.778,14.795 35.197,13.862C35.613,12.938 36.319,12.129 37.289,11.42C37.957,10.931 38.896,11.076 39.385,11.745C39.874,12.414 39.729,13.352 39.06,13.841ZM31.797,15.092C31.952,14.748 32.269,14.32 32.924,13.841C33.592,13.352 33.738,12.414 33.248,11.745C32.759,11.076 31.821,10.931 31.152,11.42C30.183,12.129 29.476,12.938 29.061,13.862C28.641,14.795 28.566,15.738 28.691,16.63C28.923,18.293 29.883,19.906 30.639,21.176L30.658,21.209C31.511,22.643 32.128,23.692 32.285,24.599C32.352,24.99 32.315,25.276 32.202,25.523C32.085,25.78 31.823,26.132 31.211,26.537C30.52,26.994 30.33,27.925 30.787,28.616C31.243,29.307 32.174,29.497 32.865,29.04C33.816,28.411 34.524,27.663 34.932,26.767C35.345,25.861 35.388,24.942 35.241,24.089C34.985,22.603 34.092,21.107 33.37,19.899L33.236,19.674C32.401,18.271 31.797,17.181 31.662,16.216C31.602,15.787 31.646,15.428 31.797,15.092ZM26.787,13.841C26.132,14.32 25.816,14.748 25.661,15.092C25.51,15.428 25.466,15.787 25.526,16.216C25.66,17.181 26.264,18.271 27.1,19.674L27.234,19.899C27.955,21.107 28.848,22.603 29.105,24.089C29.252,24.942 29.208,25.861 28.796,26.767C28.388,27.663 27.68,28.411 26.729,29.04C26.038,29.497 25.107,29.307 24.65,28.616C24.193,27.925 24.383,26.994 25.074,26.537C25.687,26.132 25.949,25.78 26.066,25.523C26.178,25.276 26.216,24.99 26.148,24.599C25.992,23.692 25.375,22.643 24.522,21.209L24.502,21.176C23.747,19.906 22.786,18.293 22.555,16.63C22.43,15.738 22.505,14.795 22.925,13.862C23.34,12.938 24.046,12.129 25.016,11.42C25.684,10.931 26.623,11.076 27.112,11.745C27.601,12.414 27.456,13.352 26.787,13.841Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_off.xml
new file mode 100644
index 0000000..649195b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_off.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_on.xml
new file mode 100644
index 0000000..62bb353
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_fan_on.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_off.xml
new file mode 100644
index 0000000..48baaf5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_off.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M41.1457,5.5455C35.3706,9.6506 46.7056,15.0654 41.1457,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M35.6907,5.5455C29.9155,9.6506 41.2505,15.0654 35.6907,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M30.2356,5.5455C24.4604,9.6506 35.7955,15.0654 30.2356,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M24,6.5455C12,6.5455 6.5454,16.9091 6.5454,24C6.5454,31.0909 12,41.4546 24,41.4546C36,41.4546 41.4545,32.5005 41.4545,25.0005"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M14.0005,24.0005L8.0005,24.5005L8.5005,28.0005L18.296,28.7261C20.3848,28.8809 22.0005,30.6207 22.0005,32.7152V41.0005H26.0005V32.7722C26.0005,30.6543 27.6514,28.9034 29.7656,28.7791L43.0005,28.0005L43.5005,24.5005L34.0005,24.0005L30.0005,22.0005H18.0005L14.0005,24.0005Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_on.xml
new file mode 100644
index 0000000..425f2f6
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_heated_steering_on.xml
@@ -0,0 +1,49 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M41.1457,5.5455C35.3706,9.6506 46.7056,15.0654 41.1457,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M35.6907,5.5455C29.9155,9.6506 41.2505,15.0654 35.6907,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M30.2356,5.5455C24.4604,9.6506 35.7955,15.0654 30.2356,18.6364"
+      android:strokeWidth="3"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M24,6.5455C12,6.5455 6.5454,16.9091 6.5454,24C6.5454,31.0909 12,41.4546 24,41.4546C36,41.4546 41.4545,32.5005 41.4545,25.0005"
+      android:strokeLineJoin="round"
+      android:strokeWidth="4"
+      android:fillColor="@android:color/transparent"
+      android:strokeColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M14.0005,24.0005L8.0005,24.5005L8.5005,28.0005L18.296,28.7261C20.3848,28.8809 22.0005,30.6207 22.0005,32.7152V41.0005H26.0005V32.7722C26.0005,30.6543 27.6514,28.9034 29.7656,28.7791L43.0005,28.0005L43.5005,24.5005L34.0005,24.0005L30.0005,22.0005H18.0005L14.0005,24.0005Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_hvac_close.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_hvac_close.xml
new file mode 100644
index 0000000..e9ae42e
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_hvac_close.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/hvac_panel_exit_icon_dimen"
+        android:height="@dimen/hvac_panel_exit_icon_dimen"
+        android:viewportWidth="26"
+        android:viewportHeight="26">
+    <path
+        android:pathData="M25.8327 2.75199L23.2477 0.166992L12.9994 10.4153L2.75102 0.166992L0.166016 2.75199L10.4144 13.0003L0.166016 23.2487L2.75102 25.8337L12.9994 15.5853L23.2477 25.8337L25.8327 23.2487L15.5844 13.0003L25.8327 2.75199Z"
+        android:fillColor="@color/hvac_off_icon_fill_color" />
+</vector>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_1.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_1.xml
new file mode 100644
index 0000000..00a1ed8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42.9713,47V38.792L41.3233,39.992L40.2673,38.376L43.4833,36.056H45.0673V47H42.9713Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_2.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_2.xml
new file mode 100644
index 0000000..3421517
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_2.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M39.3867,47V45.096C39.3867,45.096 39.4987,44.984 39.7227,44.76C39.9467,44.536 40.2294,44.2533 40.5707,43.912C40.9227,43.5707 41.2854,43.2133 41.6587,42.84C42.032,42.4667 42.3734,42.12 42.6827,41.8C42.992,41.48 43.2214,41.24 43.3707,41.08C43.744,40.6747 44.0054,40.3333 44.1547,40.056C44.304,39.7787 44.3787,39.4587 44.3787,39.096C44.3787,38.744 44.2454,38.4347 43.9787,38.168C43.712,37.9013 43.3387,37.768 42.8587,37.768C42.3787,37.768 42.0054,37.9067 41.7387,38.184C41.472,38.4613 41.2854,38.7707 41.1787,39.112L39.2907,38.328C39.408,37.9333 39.616,37.544 39.9147,37.16C40.224,36.776 40.624,36.456 41.1147,36.2C41.616,35.9333 42.208,35.8 42.8907,35.8C43.6374,35.8 44.2774,35.944 44.8107,36.232C45.3547,36.52 45.7707,36.904 46.0587,37.384C46.3574,37.864 46.5067,38.4027 46.5067,39C46.5067,39.6827 46.3414,40.312 46.0107,40.888C45.68,41.464 45.2694,41.992 44.7787,42.472C44.6187,42.6213 44.5014,42.7333 44.4267,42.808C44.3627,42.872 44.2934,42.936 44.2187,43C44.1547,43.064 44.0534,43.1653 43.9147,43.304C43.7867,43.432 43.584,43.6347 43.3067,43.912C43.04,44.1893 42.6614,44.5733 42.1707,45.064L42.2187,45.16H46.6507V47H39.3867Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_3.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_3.xml
new file mode 100644
index 0000000..58f47fe
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_3.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42.9975,47.256C42.1122,47.256 41.3068,47.0213 40.5815,46.552C39.8562,46.072 39.3548,45.3467 39.0775,44.376L41.0615,43.592C41.3282,44.68 41.9735,45.224 42.9975,45.224C43.4455,45.224 43.8402,45.0907 44.1815,44.824C44.5228,44.5467 44.6935,44.1893 44.6935,43.752C44.6935,43.2827 44.5122,42.9147 44.1495,42.648C43.7868,42.3813 43.3068,42.248 42.7095,42.248H41.7655V40.344H42.6295C43.0668,40.344 43.4562,40.232 43.7975,40.008C44.1388,39.784 44.3095,39.4373 44.3095,38.968C44.3095,38.6053 44.1762,38.3067 43.9095,38.072C43.6535,37.8373 43.3122,37.72 42.8855,37.72C42.4162,37.72 42.0535,37.848 41.7975,38.104C41.5415,38.36 41.3655,38.6427 41.2695,38.952L39.3655,38.168C39.4935,37.8053 39.7068,37.4427 40.0055,37.08C40.3042,36.7173 40.6935,36.4133 41.1735,36.168C41.6535,35.9227 42.2295,35.8 42.9015,35.8C43.6055,35.8 44.2188,35.928 44.7415,36.184C45.2748,36.44 45.6908,36.792 45.9895,37.24C46.2882,37.6773 46.4375,38.1733 46.4375,38.728C46.4375,39.3573 46.2882,39.8747 45.9895,40.28C45.7015,40.6853 45.3868,40.9733 45.0455,41.144V41.272C45.5468,41.4747 45.9682,41.8 46.3095,42.248C46.6615,42.696 46.8375,43.2613 46.8375,43.944C46.8375,44.5733 46.6775,45.1387 46.3575,45.64C46.0375,46.1413 45.5895,46.536 45.0135,46.824C44.4375,47.112 43.7655,47.256 42.9975,47.256Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_4.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_4.xml
new file mode 100644
index 0000000..077d134
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_4.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M38.7282,44.984V43.288L43.5922,36.056H45.8642V43.032H47.2242V44.984H45.8642V47H43.7682V44.984H38.7282ZM41.0482,43.032H43.7682V39.176H43.6402L41.0482,43.032Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_5.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_5.xml
new file mode 100644
index 0000000..74b7fc2
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_5.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M42.9365,47.256C42.3925,47.256 41.8485,47.1493 41.3045,46.936C40.7712,46.7227 40.3018,46.3973 39.8965,45.96C39.4912,45.5227 39.2085,44.968 39.0485,44.296L40.9365,43.56C41.0538,44.0827 41.2832,44.5093 41.6245,44.84C41.9658,45.16 42.3978,45.32 42.9205,45.32C43.4218,45.32 43.8432,45.1493 44.1845,44.808C44.5365,44.4667 44.7125,44.0347 44.7125,43.512C44.7125,43 44.5472,42.5733 44.2165,42.232C43.8858,41.88 43.4538,41.704 42.9205,41.704C42.5898,41.704 42.2965,41.7733 42.0405,41.912C41.7845,42.0507 41.5658,42.2267 41.3845,42.44L39.3525,41.528L39.9765,36.056H46.1525V37.896H41.7205L41.3205,40.456L41.4485,40.488C41.6618,40.3067 41.9232,40.152 42.2325,40.024C42.5525,39.896 42.9258,39.832 43.3525,39.832C43.9605,39.832 44.5258,39.9867 45.0485,40.296C45.5712,40.6053 45.9925,41.0373 46.3125,41.592C46.6432,42.136 46.8085,42.776 46.8085,43.512C46.8085,44.2373 46.6432,44.8827 46.3125,45.448C45.9818,46.0133 45.5232,46.456 44.9365,46.776C44.3605,47.096 43.6938,47.256 42.9365,47.256Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_6.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_6.xml
new file mode 100644
index 0000000..503c42a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_6.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M43.0392,47.256C42.4312,47.256 41.8765,47.1493 41.3752,46.936C40.8845,46.712 40.4685,46.4187 40.1272,46.056C39.4445,45.3413 39.1032,44.4667 39.1032,43.432C39.1032,42.696 39.2472,42.024 39.5352,41.416C39.8339,40.808 40.2072,40.1787 40.6552,39.528C41.0925,38.8987 41.5299,38.2693 41.9672,37.64C42.4152,37 42.8579,36.3653 43.2952,35.736L44.9272,36.856C44.5539,37.3787 44.1752,37.9067 43.7912,38.44C43.4179,38.9627 43.0445,39.4907 42.6712,40.024L42.7672,40.12C43.0125,40.0133 43.2899,39.96 43.5992,39.96C44.1539,39.96 44.6819,40.1093 45.1832,40.408C45.6845,40.7067 46.0952,41.1227 46.4152,41.656C46.7352,42.1893 46.8952,42.808 46.8952,43.512C46.8952,44.2373 46.7139,44.8827 46.3512,45.448C45.9885,46.0133 45.5139,46.456 44.9272,46.776C44.3405,47.096 43.7112,47.256 43.0392,47.256ZM42.9912,45.336C43.3219,45.336 43.6259,45.2613 43.9032,45.112C44.1805,44.952 44.4045,44.7387 44.5752,44.472C44.7565,44.1947 44.8472,43.88 44.8472,43.528C44.8472,43.1653 44.7565,42.8507 44.5752,42.584C44.4045,42.3067 44.1752,42.0933 43.8872,41.944C43.6099,41.784 43.3112,41.704 42.9912,41.704C42.6819,41.704 42.3832,41.784 42.0952,41.944C41.8179,42.0933 41.5885,42.3067 41.4072,42.584C41.2365,42.8507 41.1512,43.1653 41.1512,43.528C41.1512,43.88 41.2365,44.1947 41.4072,44.472C41.5885,44.7387 41.8179,44.952 42.0952,45.112C42.3725,45.2613 42.6712,45.336 42.9912,45.336Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_7.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_7.xml
new file mode 100644
index 0000000..bcf9158
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_7.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M41.5709,47.256L39.8109,46.28L44.3709,38.12L44.3069,38.024H39.2829V36.056H46.7229V38.12C45.8695,39.6347 45.0109,41.1547 44.1469,42.68C43.2829,44.2053 42.4242,45.7307 41.5709,47.256Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_8.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_8.xml
new file mode 100644
index 0000000..7d70370
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_8.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M43.0087,47.256C42.23,47.256 41.542,47.112 40.9447,46.824C40.3474,46.5253 39.878,46.1307 39.5367,45.64C39.206,45.1387 39.0407,44.5787 39.0407,43.96C39.0407,43.32 39.2114,42.776 39.5527,42.328C39.894,41.8693 40.278,41.5227 40.7047,41.288V41.16C40.3634,40.9253 40.0594,40.616 39.7927,40.232C39.5367,39.8373 39.4087,39.3893 39.4087,38.888C39.4087,38.3013 39.5634,37.7787 39.8727,37.32C40.182,36.8507 40.6087,36.4827 41.1527,36.216C41.6967,35.9387 42.3154,35.8 43.0087,35.8C43.702,35.8 44.3154,35.9387 44.8487,36.216C45.3927,36.4827 45.8194,36.8507 46.1287,37.32C46.4487,37.7787 46.6087,38.3013 46.6087,38.888C46.6087,39.3893 46.4754,39.8373 46.2087,40.232C45.9527,40.616 45.6487,40.9253 45.2967,41.16V41.288C45.734,41.5227 46.1234,41.8693 46.4647,42.328C46.806,42.776 46.9767,43.32 46.9767,43.96C46.9767,44.5787 46.806,45.1387 46.4647,45.64C46.134,46.1307 45.67,46.5253 45.0727,46.824C44.486,47.112 43.798,47.256 43.0087,47.256ZM43.0087,40.376C43.446,40.376 43.814,40.2533 44.1127,40.008C44.422,39.752 44.5767,39.4213 44.5767,39.016C44.5767,38.6 44.422,38.2747 44.1127,38.04C43.814,37.7947 43.446,37.672 43.0087,37.672C42.5607,37.672 42.182,37.7947 41.8727,38.04C41.574,38.2747 41.4247,38.6 41.4247,39.016C41.4247,39.4213 41.574,39.752 41.8727,40.008C42.182,40.2533 42.5607,40.376 43.0087,40.376ZM43.0087,45.32C43.5527,45.32 43.9954,45.176 44.3367,44.888C44.6887,44.6 44.8647,44.2213 44.8647,43.752C44.8647,43.304 44.6887,42.936 44.3367,42.648C43.9847,42.36 43.542,42.216 43.0087,42.216C42.4754,42.216 42.0274,42.36 41.6647,42.648C41.3127,42.936 41.1367,43.304 41.1367,43.752C41.1367,44.2213 41.3127,44.6 41.6647,44.888C42.0167,45.176 42.4647,45.32 43.0087,45.32Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_off.xml
new file mode 100644
index 0000000..9d55f5c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_mode_fan_off.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M32.68,16.72L28.1,18.36C27.74,18.1 27.34,17.86 26.94,17.68C27.28,16.02 28.2,14.52 29.66,13.56C33.7,10.88 32.36,4 26.78,4C18,4 14.32,10.02 16.72,15.32L18.36,19.9C18.1,20.26 17.86,20.66 17.68,21.06C16.02,20.72 14.52,19.8 13.56,18.34C10.88,14.3 4,15.64 4,21.22C4,30.02 10.02,33.7 15.32,31.28L19.9,29.64C20.26,29.9 20.66,30.14 21.06,30.32C20.72,31.98 19.8,33.48 18.34,34.44C14.3,37.12 15.64,44 21.22,44C30.02,44 33.7,37.98 31.28,32.68L29.64,28.1C29.9,27.74 30.14,27.34 30.32,26.94C31.98,27.28 33.48,28.2 34.44,29.66C37.12,33.68 43.98,32.34 43.98,26.76C44,18 37.98,14.32 32.68,16.72ZM24,27C22.34,27 21,25.66 21,24C21,22.34 22.34,21 24,21C25.66,21 27,22.34 27,24C27,25.66 25.66,27 24,27Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_high.xml
new file mode 100644
index 0000000..8d92c3f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_high.xml
@@ -0,0 +1,40 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_low.xml
new file mode 100644
index 0000000..eb0927a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_low.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_med.xml
new file mode 100644
index 0000000..c7471a8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_med.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_off.xml
new file mode 100644
index 0000000..f0df11c
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_cool_off.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M38.293,0H36.479C35.979,0 35.5,0.177 35.147,0.492C33.855,1.646 33.677,3.461 34.725,4.797L35.051,5.213C36.73,7.354 36.92,10.155 35.542,12.461L30.473,20.946C28.146,24.842 28.602,29.596 31.639,33.081L35.506,37.52C35.865,37.932 36.597,37.79 36.733,37.284L43.103,13.59C44.167,9.63 43.632,5.463 41.593,1.821C40.968,0.705 39.69,0 38.293,0Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M22.13,36.811H9.935C6.859,36.811 4.365,39.037 4.365,41.784V43.027C4.365,45.773 6.859,48 9.935,48H25.394C27.98,48 30.459,47.083 32.287,45.451L33.84,44.065C34.449,43.521 34.365,42.62 33.665,42.174L27.796,38.432C26.143,37.378 24.162,36.811 22.13,36.811Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M17.701,13.057L15.221,13.945C15.026,13.804 14.809,13.674 14.592,13.577C14.776,12.677 15.275,11.865 16.066,11.345C18.254,9.893 17.528,6.167 14.506,6.167C9.75,6.167 7.756,9.427 9.057,12.298L9.945,14.779C9.804,14.974 9.674,15.191 9.576,15.408C8.677,15.223 7.865,14.725 7.345,13.934C5.893,11.746 2.167,12.472 2.167,15.494C2.167,20.261 5.427,22.254 8.298,20.943L10.779,20.055C10.974,20.196 11.191,20.326 11.407,20.423C11.223,21.323 10.725,22.135 9.934,22.655C7.746,24.107 8.472,27.833 11.494,27.833C16.261,27.833 18.254,24.573 16.943,21.702L16.055,19.221C16.196,19.026 16.326,18.809 16.423,18.593C17.322,18.777 18.135,19.275 18.655,20.066C20.107,22.243 23.822,21.517 23.822,18.495C23.833,13.75 20.572,11.757 17.701,13.057ZM13,18.625C12.101,18.625 11.375,17.899 11.375,17C11.375,16.101 12.101,15.375 13,15.375C13.899,15.375 14.625,16.101 14.625,17C14.625,17.899 13.899,18.625 13,18.625Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_high.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_high.xml
new file mode 100644
index 0000000..8e5c5e3
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_high.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_low.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_low.xml
new file mode 100644
index 0000000..52cf98b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_low.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_med.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_med.xml
new file mode 100644
index 0000000..8a02789
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_med.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_off.xml
new file mode 100644
index 0000000..b407df6
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_passenger_seat_heat_off.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_tall_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="108">
+  <path
+      android:pathData="M36.479,0H38.293C39.69,0 40.968,0.705 41.593,1.821C43.632,5.463 44.167,9.63 43.103,13.59L36.733,37.284C36.597,37.79 35.865,37.932 35.506,37.52L31.639,33.081C28.602,29.596 28.146,24.842 30.473,20.946L35.542,12.461C36.92,10.155 36.73,7.354 35.051,5.213L34.725,4.797C33.677,3.461 33.855,1.646 35.147,0.492C35.5,0.177 35.979,0 36.479,0ZM9.935,36.811H22.13C24.162,36.811 26.143,37.378 27.796,38.432L33.665,42.174C34.365,42.62 34.449,43.521 33.84,44.065L32.287,45.451C30.459,47.083 27.98,48 25.394,48H9.935C6.859,48 4.365,45.773 4.365,43.027V41.784C4.365,39.037 6.859,36.811 9.935,36.811ZM23.103,13.84C22.448,14.319 22.132,14.746 21.977,15.091C21.826,15.427 21.782,15.786 21.842,16.215C21.976,17.179 22.58,18.27 23.416,19.673L23.55,19.898C24.271,21.106 25.164,22.602 25.421,24.088C25.568,24.941 25.524,25.86 25.112,26.766C24.704,27.662 23.996,28.41 23.045,29.039C22.354,29.496 21.423,29.306 20.966,28.615C20.509,27.924 20.699,26.993 21.39,26.536C22.003,26.131 22.265,25.779 22.382,25.522C22.494,25.275 22.532,24.989 22.464,24.598C22.308,23.691 21.691,22.641 20.838,21.207L20.818,21.175C20.063,19.905 19.102,18.292 18.871,16.629C18.746,15.737 18.821,14.794 19.241,13.861C19.656,12.937 20.362,12.128 21.332,11.419C22,10.93 22.939,11.075 23.428,11.744C23.917,12.412 23.772,13.351 23.103,13.84ZM15.843,15.091C15.998,14.746 16.315,14.319 16.969,13.84C17.638,13.351 17.783,12.412 17.294,11.744C16.805,11.075 15.866,10.93 15.198,11.419C14.228,12.128 13.522,12.937 13.107,13.861C12.687,14.794 12.612,15.737 12.736,16.629C12.968,18.292 13.929,19.905 14.684,21.175L14.704,21.207C15.557,22.641 16.174,23.691 16.33,24.598C16.398,24.989 16.36,25.275 16.248,25.522C16.131,25.779 15.869,26.131 15.256,26.536C14.565,26.993 14.375,27.924 14.832,28.615C15.289,29.306 16.22,29.496 16.911,29.039C17.862,28.41 18.57,27.662 18.978,26.766C19.39,25.86 19.434,24.941 19.287,24.088C19.031,22.602 18.137,21.106 17.416,19.898L17.282,19.673C16.446,18.27 15.842,17.179 15.708,16.215C15.648,15.786 15.692,15.427 15.843,15.091ZM10.831,13.84C10.177,14.319 9.86,14.746 9.705,15.091C9.554,15.427 9.51,15.786 9.57,16.215C9.705,17.179 10.309,18.27 11.144,19.673L11.278,19.898C12,21.106 12.893,22.602 13.149,24.088C13.296,24.941 13.253,25.86 12.84,26.766C12.432,27.662 11.724,28.41 10.773,29.039C10.082,29.496 9.151,29.306 8.694,28.615C8.238,27.924 8.427,26.993 9.119,26.536C9.731,26.131 9.993,25.779 10.11,25.522C10.223,25.275 10.26,24.989 10.193,24.598C10.036,23.691 9.419,22.641 8.566,21.207L8.547,21.175C7.791,19.905 6.831,18.292 6.599,16.629C6.474,15.737 6.549,14.794 6.969,13.861C7.384,12.937 8.09,12.128 9.06,11.419C9.729,10.93 10.667,11.075 11.156,11.744C11.646,12.412 11.5,13.351 10.831,13.84Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M24,79L24,79A5,5 0,0 1,29 84L29,84A5,5 0,0 1,24 89L24,89A5,5 0,0 1,19 84L19,84A5,5 0,0 1,24 79z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,97L24,97A5,5 0,0 1,29 102L29,102A5,5 0,0 1,24 107L24,107A5,5 0,0 1,19 102L19,102A5,5 0,0 1,24 97z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+  <path
+      android:pathData="M24,61L24,61A5,5 0,0 1,29 66L29,66A5,5 0,0 1,24 71L24,71A5,5 0,0 1,19 66L19,66A5,5 0,0 1,24 61z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillAlpha="@dimen/hvac_heat_or_cool_off_alpha"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_off.xml
new file mode 100644
index 0000000..aef5c8a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_off.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M26.0001,4H22.0001V24H26.0001V4ZM33.9201,14.1L36.7401,11.28C43.7601,18.32 43.7601,29.7 36.7401,36.72C29.7201,43.76 18.3201,43.76 11.3001,36.74C4.2601,29.7 4.2601,18.3 11.2801,11.28L14.1001,14.08C8.6401,19.54 8.6601,28.44 14.1201,33.9C19.5601,39.34 28.4401,39.34 33.9001,33.88C39.3601,28.42 39.3801,19.56 33.9201,14.1Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_on.xml
new file mode 100644
index 0000000..359ab84
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_power_on.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M26.0001,4H22.0001V24H26.0001V4ZM33.9201,14.1L36.7401,11.28C43.7601,18.32 43.7601,29.7 36.7401,36.72C29.7201,43.76 18.3201,43.76 11.3001,36.74C4.2601,29.7 4.2601,18.3 11.2801,11.28L14.1001,14.08C8.6401,19.54 8.6601,28.44 14.1201,33.9C19.5601,39.34 28.4401,39.34 33.9001,33.88C39.3601,28.42 39.3801,19.56 33.9201,14.1Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_off.xml
new file mode 100644
index 0000000..dbe02ed
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_off.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M12,27C12,23.14 15.5,20 19.8,20H32.34L27.16,25.18L30,28L40,18L30,8L27.18,10.82L32.34,16H19.8C13.3,16 8,20.94 8,27C8,33.06 13.3,38 19.8,38H34V34H19.8C15.5,34 12,30.86 12,27Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_on.xml
new file mode 100644
index 0000000..55aa087
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_recirculate_on.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M12,27C12,23.14 15.5,20 19.8,20H32.34L27.16,25.18L30,28L40,18L30,8L27.18,10.82L32.34,16H19.8C13.3,16 8,20.94 8,27C8,33.06 13.3,38 19.8,38H34V34H19.8C15.5,34 12,30.86 12,27Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_off.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_off.xml
new file mode 100644
index 0000000..97698d7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_off.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M33.6001,24.0001L40.8001,16.8001L33.6001,9.6001V14.4001H9.6001V19.2001H33.6001V24.0001Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+  <path
+      android:pathData="M14.4002,24L7.2002,31.2L14.4002,38.4V33.6H38.4002V28.8H14.4002V24Z"
+      android:fillColor="@color/hvac_off_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_on.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_on.xml
new file mode 100644
index 0000000..ab3b3ab
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/ic_sync_on.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/hvac_panel_icon_dimen"
+    android:height="@dimen/hvac_panel_icon_dimen"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M33.6001,24.0001L40.8001,16.8001L33.6001,9.6001V14.4001H9.6001V19.2001H33.6001V24.0001Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+  <path
+      android:pathData="M14.4002,24L7.2002,31.2L14.4002,38.4V33.6H38.4002V28.8H14.4002V24Z"
+      android:fillColor="@color/hvac_on_icon_fill_color"/>
+</vector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
new file mode 100644
index 0000000..3f7700b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/drawable/nav_bar_button_background.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true">
+        <layer-list>
+            <item>
+                <shape android:shape="oval">
+                    <size android:width="@dimen/system_bar_button_size"
+                          android:height="@dimen/system_bar_button_size"/>
+                    <solid android:color="@color/car_nav_icon_fill_color"/>
+                </shape>
+            </item>
+            <item>
+                <ripple android:color="@color/car_ui_ripple_color"
+                        android:radius="@dimen/system_bar_icon_drawing_size"/>
+            </item>
+        </layer-list>
+    </item>
+    <item>
+        <layer-list>
+            <item>
+                <shape android:shape="oval">
+                    <size android:width="@dimen/system_bar_button_size"
+                          android:height="@dimen/system_bar_button_size"/>
+                    <solid android:color="@color/car_nav_icon_background_color"/>
+                </shape>
+            </item>
+            <item>
+                <ripple android:color="@color/car_ui_ripple_color"
+                        android:radius="@dimen/system_bar_icon_drawing_size"/>
+            </item>
+        </layer-list>
+    </item>
+</selector>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
new file mode 100644
index 0000000..63c841b
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_bottom_system_bar.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<com.android.systemui.car.systembar.CarSystemBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/system_bar_background"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <com.android.systemui.car.hvac.TemperatureControlView
+            android:id="@+id/driver_hvac"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:layout_gravity="start"
+            android:gravity="start|center_vertical"
+            systemui:hvacAreaId="49">
+            <include layout="@layout/adjustable_temperature_view"/>
+        </com.android.systemui.car.hvac.TemperatureControlView>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:layoutDirection="ltr">
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/grid_nav"
+                style="@style/SystemBarButton"
+                systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_apps"
+                systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
+                systemui:clearBackStack="true"/>
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/notifications"
+                style="@style/SystemBarButton"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_notification"
+                systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
+
+            <com.android.systemui.car.systembar.CarSystemBarButton
+                android:id="@+id/hvac"
+                style="@style/SystemBarButton"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_hvac"
+                systemui:broadcast="true"/>
+
+            <com.android.systemui.car.systembar.AssitantButton
+                android:id="@+id/assist"
+                style="@style/SystemBarButton"
+                systemui:highlightWhenSelected="true"
+                systemui:icon="@drawable/car_ic_mic"
+                systemui:useDefaultAppIconForRole="false"/>
+        </LinearLayout>
+
+        <com.android.systemui.car.hvac.TemperatureControlView
+            android:id="@+id/passenger_hvac"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="end"
+            android:layout_weight="1"
+            android:gravity="end|center_vertical"
+            systemui:hvacAreaId="68">
+            <include layout="@layout/adjustable_temperature_view"/>
+        </com.android.systemui.car.hvac.TemperatureControlView>
+
+    </LinearLayout>
+</com.android.systemui.car.systembar.CarSystemBarView>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
new file mode 100644
index 0000000..e30ec45
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/car_top_system_bar.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<com.android.systemui.car.systembar.CarSystemBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/car_top_bar"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/status_bar_background"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <com.android.systemui.car.systembar.CarSystemBarButton
+        android:id="@+id/user_name"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/car_padding_3"
+        android:layout_gravity="start"
+        android:gravity="start"
+        android:orientation="horizontal"
+        systemui:intent="intent:#Intent;component=com.android.car.settings/.profiles.ProfileSwitcherActivity;launchFlags=0x24000000;end">
+            <ImageView
+                android:id="@+id/user_avatar"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:src="@drawable/car_ic_user_icon"
+                android:layout_marginEnd="@dimen/system_bar_user_icon_padding"/>
+            <TextView
+                android:id="@+id/user_name_text"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:textAppearance="@style/TextAppearance.SystemBar.Username"
+                android:maxLines="1"
+                android:maxLength="10"/>
+    </com.android.systemui.car.systembar.CarSystemBarButton>
+
+    <com.android.systemui.statusbar.policy.Clock
+        android:id="@+id/clock"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:layout_gravity="center"
+        android:gravity="center"
+        android:paddingStart="@dimen/car_padding_2"
+        android:paddingEnd="@dimen/car_padding_2"
+        android:elevation="5dp"
+        android:singleLine="true"
+        android:textAppearance="@style/TextAppearance.SystemBar.Clock"
+        systemui:amPmStyle="normal"/>
+
+    <com.android.systemui.car.systembar.CarSystemBarButton
+        android:id="@+id/system_icon_area"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="@dimen/car_padding_3"
+        android:layout_gravity="end"
+        android:gravity="end"
+        systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$HomepageActivity;launchFlags=0x24000000;end">
+
+        <com.android.systemui.statusbar.phone.StatusIconContainer
+            android:id="@+id/statusIcons"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="fitCenter"
+            android:gravity="center"
+            android:orientation="horizontal"
+        />
+    </com.android.systemui.car.systembar.CarSystemBarButton>
+</com.android.systemui.car.systembar.CarSystemBarView>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/fan_direction.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/fan_direction.xml
new file mode 100644
index 0000000..5cbe9e7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/fan_direction.xml
@@ -0,0 +1,110 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:systemui="http://schemas.android.com/apk/res-auto"
+       android:layout_width="match_parent"
+       android:layout_height="match_parent">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/direction_face"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="356517121"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_airflow_head_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_airflow_head_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"
+            systemui:preventToggleOff="true"/>
+        <View
+            android:layout_width="32dp"
+            android:layout_height="match_parent"/>
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/direction_floor"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="356517121"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_airflow_feet_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_airflow_feet_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="2"
+            systemui:offValue="0"
+            systemui:preventToggleOff="true"/>
+        <View
+            android:layout_width="32dp"
+            android:layout_height="match_parent"/>
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/direction_defrost_front_and_floor"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="356517121"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_airflow_windshield_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_airflow_windshield_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="6"
+            systemui:offValue="0"
+            systemui:preventToggleOff="true"/>
+    </LinearLayout>
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="32dp"/>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/direction_defrost_front"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="1"
+            systemui:hvacPropertyId="320865540"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_defroster_windshield_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_defroster_windshield_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"/>
+        <View
+            android:layout_width="32dp"
+            android:layout_height="match_parent"/>
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/direction_defrost_rear"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_weight="1"
+            android:background="@drawable/hvac_default_background"
+            systemui:hvacAreaId="2"
+            systemui:hvacPropertyId="320865540"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_defroster_rear_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_defroster_rear_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"/>
+    </LinearLayout>
+</merge>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml
new file mode 100644
index 0000000..f92c857
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_container.xml
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<com.android.car.ui.FocusArea
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/hvac_panel_container"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/hvac_panel_full_expanded_height"
+    android:layout_gravity="bottom">
+    <com.android.systemui.car.hvac.HvacPanelView
+        android:id="@+id/hvac_panel"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/hvac_panel_bg">
+
+        <ImageButton
+            android:id="@+id/hvac_panel_close_button"
+            android:layout_width="@dimen/hvac_panel_exit_button_dimen"
+            android:layout_height="@dimen/hvac_panel_exit_button_dimen"
+            android:layout_marginLeft="@dimen/hvac_panel_exit_button_margin"
+            android:layout_marginTop="@dimen/hvac_panel_exit_button_margin"
+            android:background="@drawable/hvac_default_background"
+            android:scaleType="center"
+            android:src="@drawable/ic_hvac_close"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"/>
+        <FrameLayout
+            android:id="@+id/hvac_header_title"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/wrap_content"
+            android:layout_marginTop="@dimen/hvac_panel_title_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_dimen"
+            android:layout_marginRight="@dimen/hvac_panel_button_dimen"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent">
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:text="@string/hvac_panel_header"
+                android:gravity="center"/>
+        </FrameLayout>
+
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/top_guideline"
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:orientation="horizontal"
+            app:layout_constraintGuide_begin="@dimen/hvac_panel_buttons_guideline"/>
+
+        <!-- ************************ -->
+        <!-- First column of buttons. -->
+        <!-- ************************ -->
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/cooling_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toTopOf="@+id/steering_wheel_heat_on_off"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419973"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_ac_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_ac_on"
+            systemui:hvacTurnOffIfAutoOn="true"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacIntegerToggleButton
+            android:id="@+id/steering_wheel_heat_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_heat_background"
+            app:layout_constraintBottom_toTopOf="@+id/hvac_on_off"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/cooling_on_off"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="289408269"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_heated_steering_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_heated_steering_on"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:onValue="1"
+            systemui:offValue="0"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/hvac_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/steering_wheel_heat_on_off"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419984"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_power_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_power_on"
+            systemui:hvacTurnOffIfPowerOff="false"/>
+
+        <!-- ************************* -->
+        <!-- Second column of buttons. -->
+        <!-- ************************* -->
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_cooler_driver_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_cool_background"
+            app:layout_constraintBottom_toTopOf="@+id/seat_heater_driver_on_off"
+            app:layout_constraintLeft_toRightOf="@+id/cooling_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/airflow_group"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="1"
+            systemui:seatTemperatureType="cooling"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_driver_seat_cool_icons"/>
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_heater_driver_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_heat_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toRightOf="@+id/hvac_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/fan_speed_control"
+            app:layout_constraintTop_toBottomOf="@+id/seat_cooler_driver_on_off"
+            systemui:hvacAreaId="1"
+            systemui:seatTemperatureType="heating"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_driver_seat_heat_icons"/>
+
+        <!-- ************************ -->
+        <!-- Third column of buttons. -->
+        <!-- ************************ -->
+
+        <LinearLayout
+            android:id="@+id/airflow_group"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:orientation="vertical"
+            app:layout_constraintBottom_toTopOf="@+id/fan_speed_control"
+            app:layout_constraintLeft_toRightOf="@+id/seat_cooler_driver_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/seat_cooler_passenger_on_off"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline">
+           <include layout="@layout/fan_direction"/>
+        </LinearLayout>
+
+        <com.android.systemui.car.hvac.custom.FanSpeedSeekBar
+            android:id="@+id/fan_speed_control"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:progressDrawable="@drawable/fan_speed_seek_bar"
+            android:thumb="@drawable/fan_speed_seek_bar_thumb"
+            android:maxHeight="@dimen/hvac_panel_button_dimen"
+            android:minHeight="@dimen/hvac_panel_button_dimen"
+            android:background="@drawable/fan_speed_seek_bar_background"
+            android:splitTrack="false"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toRightOf="@+id/seat_heater_driver_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/seat_heater_passenger_on_off"
+            app:layout_constraintTop_toBottomOf="@+id/airflow_windshield"/>
+
+        <!-- ************************* -->
+        <!-- Fourth column of buttons. -->
+        <!-- ************************* -->
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_cooler_passenger_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_cool_background"
+            app:layout_constraintBottom_toTopOf="@+id/seat_heater_passenger_on_off"
+            app:layout_constraintRight_toLeftOf="@+id/recycle_air_on_off"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="4"
+            systemui:seatTemperatureType="cooling"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_passenger_seat_cool_icons"/>
+
+        <com.android.systemui.car.hvac.SeatTemperatureLevelButton
+            android:id="@+id/seat_heater_passenger_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_tall_button_height"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_heat_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toLeftOf="@+id/hvac_driver_passenger_sync"
+            app:layout_constraintTop_toBottomOf="@+id/seat_cooler_passenger_on_off"
+            systemui:hvacAreaId="4"
+            systemui:seatTemperatureType="heating"
+            systemui:seatTemperatureIconDrawableList="@array/hvac_passenger_seat_heat_icons"/>
+
+        <!-- ************************ -->
+        <!-- Fifth column of buttons. -->
+        <!-- ************************ -->
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/recycle_air_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toTopOf="@+id/hvac_driver_passenger_sync"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/top_guideline"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419986"
+            systemui:hvacTurnOffIfAutoOn="true"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_recirculate_on"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_recirculate_off"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/hvac_driver_passenger_sync"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toTopOf="@+id/auto_temperature_on_off"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/recycle_air_on_off"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419977"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_sync_off"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_sync_on"
+            systemui:hvacTurnOffIfAutoOn="true"/>
+
+        <com.android.systemui.car.hvac.toggle.HvacBooleanToggleButton
+            android:id="@+id/auto_temperature_on_off"
+            android:layout_width="@dimen/hvac_panel_button_dimen"
+            android:layout_height="@dimen/hvac_panel_button_dimen"
+            android:layout_marginBottom="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginLeft="@dimen/hvac_panel_button_internal_margin"
+            android:layout_marginRight="@dimen/hvac_panel_button_external_margin"
+            android:layout_marginTop="@dimen/hvac_panel_button_internal_margin"
+            android:background="@drawable/hvac_default_background"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/hvac_driver_passenger_sync"
+            systemui:hvacAreaId="117"
+            systemui:hvacPropertyId="354419978"
+            systemui:hvacToggleOnButtonDrawable="@drawable/ic_auto_on"
+            systemui:hvacToggleOffButtonDrawable="@drawable/ic_auto_off"/>
+
+        <include
+            layout="@layout/hvac_panel_handle_bar"
+            app:layout_constraintTop_toTopOf="parent"/>
+    </com.android.systemui.car.hvac.HvacPanelView>
+</com.android.car.ui.FocusArea>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_handle_bar.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_handle_bar.xml
new file mode 100644
index 0000000..0ebd055
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/hvac_panel_handle_bar.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <View
+        android:id="@+id/handle_bar"
+        android:layout_width="@dimen/hvac_panel_handle_bar_width"
+        android:layout_height="@dimen/hvac_panel_handle_bar_height"
+        android:layout_marginTop="@dimen/hvac_panel_handle_bar_margin_top"
+        android:layout_gravity="top|center_horizontal"
+        android:background="@drawable/hvac_panel_handle_bar"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml
new file mode 100644
index 0000000..a7631d7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/layout/rear_view_camera.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/transparent">
+    <LinearLayout
+        android:id="@+id/rear_view_camera_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"/>
+    <ImageButton
+        android:id="@+id/close_button"
+        android:layout_width="@dimen/rear_view_camera_exit_button_width"
+        android:layout_height="@dimen/rear_view_camera_exit_button_height"
+        android:layout_marginStart="@dimen/rear_view_camera_exit_button_margin"
+        android:layout_marginTop="@dimen/rear_view_camera_exit_button_margin"
+        android:scaleType="center"
+        android:src="@drawable/ic_close"
+        android:background="@drawable/exit_icon_background"/>
+</FrameLayout>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/arrays.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/arrays.xml
new file mode 100644
index 0000000..c1c2119
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/arrays.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.
+ -->
+
+<resources>
+    <array name="hvac_driver_seat_heat_icons">
+        <item>@drawable/ic_driver_seat_heat_off</item>
+        <item>@drawable/ic_driver_seat_heat_low</item>
+        <item>@drawable/ic_driver_seat_heat_med</item>
+        <item>@drawable/ic_driver_seat_heat_high</item>
+    </array>
+    <array name="hvac_passenger_seat_heat_icons">
+        <item>@drawable/ic_passenger_seat_heat_off</item>
+        <item>@drawable/ic_passenger_seat_heat_low</item>
+        <item>@drawable/ic_passenger_seat_heat_med</item>
+        <item>@drawable/ic_passenger_seat_heat_high</item>
+    </array>
+    <array name="hvac_driver_seat_cool_icons">
+        <item>@drawable/ic_driver_seat_cool_off</item>
+        <item>@drawable/ic_driver_seat_cool_low</item>
+        <item>@drawable/ic_driver_seat_cool_med</item>
+        <item>@drawable/ic_driver_seat_cool_high</item>
+    </array>
+    <array name="hvac_passenger_seat_cool_icons">
+        <item>@drawable/ic_passenger_seat_cool_off</item>
+        <item>@drawable/ic_passenger_seat_cool_low</item>
+        <item>@drawable/ic_passenger_seat_cool_med</item>
+        <item>@drawable/ic_passenger_seat_cool_high</item>
+    </array>
+    <array name="hvac_fan_speed_icons">
+        <item>@drawable/fan_speed_seek_bar_thumb_off</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_1</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_2</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_3</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_4</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_5</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_6</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_7</item>
+        <item>@drawable/fan_speed_seek_bar_thumb_8</item>
+    </array>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/attrs.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/attrs.xml
new file mode 100644
index 0000000..120905f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/attrs.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <declare-styleable name="FanSpeedSeekBar">
+        <!-- List of drawables that will be shown when the seat heat level button is clicked.
+             This list should have exactly R.integer.hvac_seat_heat_level_count items.
+             The first item should have the "off" drawable. -->
+        <attr name="fanSpeedThumbIcons" format="reference"/>
+    </declare-styleable>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
new file mode 100644
index 0000000..248a2c8
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/colors.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <color name="rear_view_camera_button_background">#CCFFFFFF</color>
+    <color name="rear_view_camera_exit_icon_color">@android:color/black</color>
+
+    <color name="car_nav_icon_fill_color">#FFFFFF</color>
+    <color name="car_nav_icon_background_color">#3C4043</color>
+
+    <drawable name="system_bar_background">#000000</drawable>
+
+    <color name="status_bar_background_color">#00000000</color>
+    <drawable name="status_bar_background">@color/status_bar_background_color</drawable>
+
+    <color name="hvac_background_color">#202124</color>
+    <color name="hvac_master_switch_color">@color/car_nav_icon_fill_color</color>
+    <color name="hvac_on_icon_fill_color">@android:color/black</color>
+    <color name="hvac_off_icon_fill_color">@android:color/white</color>
+    <color name="hvac_on_cooling_background_color">#669DF6</color>
+    <color name="hvac_on_heating_background_color">#EE675C</color>
+    <color name="hvac_on_background_color">#50E3C2</color>
+    <color name="hvac_off_background_color">#3C4043</color>
+
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
new file mode 100644
index 0000000..ecd31f7
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <string name="config_systemUIFactoryComponent" translatable="false">
+        com.android.systemui.CarUiPortraitSystemUIFactory
+    </string>
+
+    <!-- Car System UI's OverlayViewsMediator.
+         Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
+    <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
+        <item>@string/config_notificationPanelViewMediator</item>
+        <item>com.android.systemui.car.hvac.HvacPanelOverlayViewMediator</item>
+        <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
+        <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
+        <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
+    </string-array>
+
+    <!-- Show heads-up notifications on the bottom -->
+    <bool name="config_showHeadsUpNotificationOnBottom">true</bool>
+
+    <string name="config_notificationPanelViewMediator" translatable="false">
+        com.android.systemui.car.notification.BottomNotificationPanelViewMediator</string>
+
+    <!-- Animation helper for animating heads-up notification showing on screen and leaving the screen from the bottom -->
+    <string name="config_headsUpNotificationAnimationHelper" translatable="false">
+        com.android.car.notification.headsup.animationhelper.CarHeadsUpNotificationBottomAnimationHelper</string>
+
+    <integer name="hvac_num_fan_speeds">9</integer>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
new file mode 100644
index 0000000..6a961fd
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/dimens.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <!-- dimensions for rear view camera -->
+    <dimen name="rear_view_camera_width">1020dp</dimen>
+    <dimen name="rear_view_camera_height">720dp</dimen>
+
+    <dimen name="rear_view_camera_exit_button_width">48dp</dimen>
+    <dimen name="rear_view_camera_exit_button_height">48dp</dimen>
+    <dimen name="rear_view_camera_exit_button_margin">24dp</dimen>
+    <dimen name="rear_view_camera_exit_icon_width">26dp</dimen>
+    <dimen name="rear_view_camera_exit_icon_height">26dp</dimen>
+
+    <dimen name="hvac_container_padding">16dp</dimen>
+    <dimen name="hvac_temperature_text_size">48sp</dimen>
+    <dimen name="hvac_temperature_text_padding">0dp</dimen>
+
+    <dimen name="system_bar_icon_drawing_size">56dp</dimen>
+    <dimen name="system_bar_button_size">88dp</dimen>
+    <!-- Margin between the system bar buttons -->
+    <dimen name="system_bar_button_margin">32dp</dimen>
+    <!-- Padding between the system bar button and the icon within it -->
+    <dimen name="system_bar_button_padding">16dp</dimen>
+
+    <dimen name="system_bar_user_icon_drawing_size">44dp</dimen>
+    <dimen name="status_bar_system_icon_spacing">32dp</dimen>
+
+    <dimen name="hvac_panel_handle_bar_height">6dp</dimen>
+    <dimen name="hvac_panel_handle_bar_margin_top">8dp</dimen>
+    <dimen name="hvac_panel_handle_bar_width">64dp</dimen>
+    <dimen name="hvac_panel_bg_radius">24dp</dimen>
+    <dimen name="hvac_panel_off_button_radius">24dp</dimen>
+    <dimen name="hvac_panel_on_button_radius">44dp</dimen>
+    <dimen name="hvac_panel_full_expanded_height">472dp</dimen>
+    <dimen name="hvac_panel_exit_icon_dimen">21dp</dimen>
+    <dimen name="hvac_panel_exit_button_dimen">64dp</dimen>
+    <dimen name="hvac_panel_exit_button_margin">24dp</dimen>
+    <dimen name="hvac_panel_title_margin">36dp</dimen>
+    <dimen name="hvac_panel_buttons_guideline">120dp</dimen>
+    <dimen name="hvac_panel_icon_dimen">48dp</dimen>
+    <dimen name="hvac_panel_tall_icon_dimen">108dp</dimen>
+    <dimen name="hvac_panel_wide_icon_dimen">96dp</dimen>
+    <dimen name="hvac_panel_icon_inset_dimen">22dp</dimen>
+    <dimen name="hvac_panel_icon_inset_wide_dimen">92dp</dimen>
+    <dimen name="hvac_panel_icon_inset_extra_wide_dimen">140dp</dimen>
+    <dimen name="hvac_panel_button_dimen">88dp</dimen>
+    <dimen name="hvac_panel_tall_button_height">148dp</dimen>
+    <dimen name="hvac_panel_wide_button_width">374dp</dimen>
+    <dimen name="hvac_panel_slider_width">696dp</dimen>
+    <dimen name="hvac_panel_button_external_margin">24dp</dimen>
+    <dimen name="hvac_panel_button_internal_margin">16dp</dimen>
+    <item name="hvac_heat_or_cool_off_alpha" format="float" type="dimen">0.3</item>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
new file mode 100644
index 0000000..c9cff07
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Format for temperature in the temperature control view (No decimal) -->
+    <string name="hvac_temperature_format_fahrenheit" translatable="false">%.0f</string>
+
+    <!-- HVAC panel header [CHAR LIMIT=40]-->
+    <string name="hvac_panel_header">Comfort controls</string>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
new file mode 100644
index 0000000..6e400e5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/styles.xml
@@ -0,0 +1,33 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="SystemBarButton">
+        <item name="android:layout_width">@dimen/system_bar_button_size</item>
+        <item name="android:layout_height">@dimen/system_bar_button_size</item>
+        <item name="android:background">@drawable/nav_bar_button_background</item>
+        <item name="android:gravity">center</item>
+        <item name="unselectedAlpha">1.0</item>
+    </style>
+
+    <style name="TextAppearance.SystemBar.Username"
+           parent="@android:style/TextAppearance.DeviceDefault">
+        <item name="android:textSize">@dimen/car_body1_size</item>
+        <item name="android:textColor">@color/system_bar_text_color</item>
+    </style>
+</resources>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitGlobalRootComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitGlobalRootComponent.java
new file mode 100644
index 0000000..af85885
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitGlobalRootComponent.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import com.android.systemui.dagger.GlobalModule;
+import com.android.systemui.dagger.WMModule;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+/**
+ * Root Component for Dagger injection for CarUiPortraitSystemUI
+ */
+@Singleton
+@Component(
+        modules = {
+                GlobalModule.class,
+                CarUiPortraitSysUIComponentModule.class,
+                WMModule.class
+        })
+interface CarUiPortraitGlobalRootComponent extends CarGlobalRootComponent {
+    @Component.Builder
+    interface Builder extends CarGlobalRootComponent.Builder {
+        CarUiPortraitGlobalRootComponent build();
+    }
+
+    @Override
+    CarUiPortraitSysUIComponent.Builder getSysUIComponent();
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
new file mode 100644
index 0000000..25e488f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponent.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import com.android.systemui.dagger.DependencyProvider;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.SystemUIModule;
+
+import dagger.Subcomponent;
+
+/**
+ * Dagger Subcomponent for Core SysUI.
+ */
+@SysUISingleton
+@Subcomponent(modules = {
+        CarComponentBinder.class,
+        DependencyProvider.class,
+        SystemUIModule.class,
+        CarSystemUIModule.class,
+        CarUiPortraitSystemUIBinder.class})
+public interface CarUiPortraitSysUIComponent extends CarSysUIComponent {
+    /**
+     * Builder for a CarSysUIComponent.
+     */
+    @Subcomponent.Builder
+    interface Builder extends CarSysUIComponent.Builder {
+        CarUiPortraitSysUIComponent build();
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponentModule.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponentModule.java
new file mode 100644
index 0000000..196c917
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSysUIComponentModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import dagger.Binds;
+import dagger.Module;
+
+/**
+ * Dagger module for including the CarUiPortraitSysUIComponent.
+ *
+ * TODO(b/162923491): Remove or otherwise refactor this module. This is a stop gap.
+ */
+@Module(subcomponents = {CarUiPortraitSysUIComponent.class})
+public abstract class CarUiPortraitSysUIComponentModule {
+    @Binds
+    abstract CarGlobalRootComponent bindSystemUIRootComponent(
+            CarUiPortraitGlobalRootComponent systemUIRootComponent);
+}
diff --git a/cpp/surround_view/app/shader.h b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
similarity index 66%
rename from cpp/surround_view/app/shader.h
rename to car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
index 63d5795..a7cddb8 100644
--- a/cpp/surround_view/app/shader.h
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIBinder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef SHADER_H
-#define SHADER_H
+package com.android.systemui;
 
-#include <GLES2/gl2.h>
+import dagger.Module;
 
-// Create a program object given vertex and pixels shader source
-GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name);
-
-#endif // SHADER_H
+/** Binder for AAECarSystemUI specific {@link SystemUI} modules and components. */
+@Module
+abstract class CarUiPortraitSystemUIBinder extends CarSystemUIBinder {
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java
new file mode 100644
index 0000000..ef75f48
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/CarUiPortraitSystemUIFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+
+import com.android.systemui.dagger.GlobalRootComponent;
+
+/**
+ * Class factory to provide AAECarSystemUI specific SystemUI components.
+ */
+public class CarUiPortraitSystemUIFactory extends CarSystemUIFactory {
+    @Override
+    protected GlobalRootComponent buildGlobalRootComponent(Context context) {
+        return DaggerCarUiPortraitGlobalRootComponent.builder().context(context).build();
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/custom/FanSpeedSeekBar.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/custom/FanSpeedSeekBar.java
new file mode 100644
index 0000000..c7f2b5f
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/hvac/custom/FanSpeedSeekBar.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.hvac.custom;
+
+import static android.car.VehiclePropertyIds.HVAC_AUTO_ON;
+import static android.car.VehiclePropertyIds.HVAC_FAN_SPEED;
+import static android.car.VehiclePropertyIds.HVAC_POWER_ON;
+
+import android.car.hardware.CarPropertyValue;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.widget.SeekBar;
+
+import androidx.annotation.ArrayRes;
+
+import com.android.systemui.R;
+import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.hvac.HvacPropertySetter;
+import com.android.systemui.car.hvac.HvacView;
+
+/** Custom seek bar to control fan speed. */
+public class FanSpeedSeekBar extends SeekBar implements HvacView {
+
+    private final SparseArray<Drawable> mIcons = new SparseArray<>();
+
+    private HvacPropertySetter mHvacPropertySetter;
+    private int mHvacGlobalAreaId;
+
+    private boolean mPowerOn;
+    private boolean mAutoOn;
+
+    private float mOnAlpha;
+    private float mOffAlpha;
+
+    private final OnSeekBarChangeListener mSeekBarChangeListener = new OnSeekBarChangeListener() {
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            int prevProgress = getProgress();
+            // Limit updates to the hvac property to be only those that come from the user in order
+            // to avoid an infinite loop.
+            if (shouldAllowControl() && fromUser && progress == prevProgress) {
+                mHvacPropertySetter.setHvacProperty(HVAC_FAN_SPEED, getAreaId(), progress);
+            } else if (progress != prevProgress) {
+                // There is an edge case with seek bar touch handling that can lead to an
+                // inconsistent state of the progress state and UI. We need to set the progress to
+                // a different value before setting it to the value we expect in order to ensure
+                // that the update doesn't get dropped.
+                setProgress(progress);
+                setProgress(prevProgress);
+                updateUI();
+            }
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+            // no-op.
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            // no-op.
+        }
+    };
+
+    public FanSpeedSeekBar(Context context) {
+        super(context);
+        init(null);
+    }
+
+    public FanSpeedSeekBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(attrs);
+    }
+
+    public FanSpeedSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(attrs);
+    }
+
+    public FanSpeedSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(attrs);
+    }
+
+    private void init(AttributeSet attrs) {
+        int speeds = mContext.getResources().getInteger(R.integer.hvac_num_fan_speeds);
+        setMin(0);
+        incrementProgressBy(1);
+        // Subtract 1 since we're starting from 0.
+        setMax(speeds - 1);
+        int thumbRadius = mContext.getResources().getDimensionPixelSize(
+                R.dimen.hvac_panel_on_button_radius);
+        setPadding(thumbRadius, 0, thumbRadius, 0);
+        mHvacGlobalAreaId = mContext.getResources().getInteger(R.integer.hvac_global_area_id);
+
+        mOnAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_on_alpha);
+        mOffAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_off_alpha);
+
+        if (attrs == null) {
+            return;
+        }
+
+        // Get fan speed thumb drawables.
+        TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.FanSpeedSeekBar);
+        @ArrayRes int drawableListRes = typedArray.getResourceId(
+                R.styleable.FanSpeedSeekBar_fanSpeedThumbIcons,
+                R.array.hvac_fan_speed_icons);
+
+        TypedArray fanSpeedThumbIcons = mContext.getResources().obtainTypedArray(drawableListRes);
+        if (fanSpeedThumbIcons.length() != speeds) {
+            throw new IllegalArgumentException(
+                    "R.styeable.SeatHeatLevelButton_seatHeaterIconDrawableList should have the "
+                            + "same length as R.integer.hvac_seat_heat_level_count");
+        }
+
+        for (int i = 0; i < speeds; i++) {
+            mIcons.set(i, fanSpeedThumbIcons.getDrawable(i));
+        }
+        fanSpeedThumbIcons.recycle();
+        typedArray.recycle();
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setOnSeekBarChangeListener(mSeekBarChangeListener);
+    }
+
+    @Override
+    public void setHvacPropertySetter(HvacPropertySetter hvacPropertySetter) {
+        mHvacPropertySetter = hvacPropertySetter;
+    }
+
+    @Override
+    public void onHvacTemperatureUnitChanged(boolean usesFahrenheit) {
+        // no-op.
+    }
+
+    @Override
+    public void onPropertyChanged(CarPropertyValue value) {
+        if (value.getPropertyId() == HVAC_FAN_SPEED) {
+            int level = (int) value.getValue();
+            setProgress(level, /* animate= */ true);
+        }
+
+        if (value.getPropertyId() == HVAC_POWER_ON) {
+            mPowerOn = (boolean) value.getValue();
+        }
+
+        if (value.getPropertyId() == HVAC_AUTO_ON) {
+            mAutoOn = (boolean) value.getValue();
+        }
+
+        updateUI();
+    }
+
+    @Override
+    public @HvacController.HvacProperty Integer getHvacPropertyToView() {
+        return HVAC_FAN_SPEED;
+    }
+
+    @Override
+    public @HvacController.AreaId Integer getAreaId() {
+        return mHvacGlobalAreaId;
+    }
+
+    private void updateUI() {
+        int progress = getProgress();
+        setThumb(mIcons.get(progress));
+        setSelected(progress > 0);
+        setAlpha(shouldAllowControl() ? mOnAlpha : mOffAlpha);
+        // Steal touch events if shouldn't allow control.
+        setOnTouchListener(shouldAllowControl() ? null : (v, event) -> true);
+    }
+
+    private boolean shouldAllowControl() {
+        return mPowerOn && !mAutoOn;
+    }
+}
diff --git a/car_product/car_ui_portrait/apps/HideApps/Android.mk b/car_product/car_ui_portrait/apps/HideApps/Android.mk
new file mode 100644
index 0000000..3dc4adf
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/HideApps/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2021 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_PACKAGE_NAME := CarUiPortraitHideApps
+LOCAL_SDK_VERSION := current
+
+# Add packages here to remove them from the build
+LOCAL_OVERRIDES_PACKAGES := \
+    CarRotaryController \
+    RotaryPlayground \
+    RotaryIME \
+    CarRotaryImeRRO \
+
+include $(BUILD_PACKAGE)
diff --git a/car_product/car_ui_portrait/apps/HideApps/AndroidManifest.xml b/car_product/car_ui_portrait/apps/HideApps/AndroidManifest.xml
new file mode 100644
index 0000000..a234af5
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/HideApps/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.car.caruiportrait.hideapps">
+    <application
+        android:allowBackup="false"
+        android:debuggable="false"
+        android:label="CarUiPortraitHideApps">
+    </application>
+</manifest>
diff --git a/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk b/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
new file mode 100644
index 0000000..1a3d48a
--- /dev/null
+++ b/car_product/car_ui_portrait/apps/car_ui_portrait_apps.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2021 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.
+#
+
+# All apps that should be included in CarUiPortrait builds
+PRODUCT_PACKAGES += \
+    CarUiPortraitSettings \
+    CarUiPortraitSystemUI \
+
+# All apps to be excluded in car_ui_portrait builds should be specified as part of CarUiPortraitHideApps.
+PRODUCT_PACKAGES += \
+    CarUiPortraitHideApps
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/car_ui_portrait.ini b/car_product/car_ui_portrait/car_ui_portrait.ini
index 6432938..ec34d7f 100644
--- a/car_product/car_ui_portrait/car_ui_portrait.ini
+++ b/car_product/car_ui_portrait/car_ui_portrait.ini
@@ -5,7 +5,7 @@
 hw.camera.front=none
 hw.mainKeys=no
 skin.dynamic=yes
-skin.name=1068x1425
-skin.path=1068x1425
-hw.lcd.width=1068
-hw.lcd.height=1425
\ No newline at end of file
+skin.name=1080x1920
+skin.path=1080x1920
+hw.lcd.width=1080
+hw.lcd.height=1920
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml
index 4fadc62..a4aa16b 100644
--- a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml
+++ b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values-sw900dp/dimens.xml
@@ -16,6 +16,6 @@
   -->
 <resources>
     <!-- Height of the bottom navigation / climate bar. -->
-    <dimen name="navigation_bar_height">136dp</dimen>
-    <dimen name="navigation_bar_height_landscape">136dp</dimen>
+    <dimen name="navigation_bar_height">160dp</dimen>
+    <dimen name="navigation_bar_height_landscape">160dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml
index 5e02ee8..e78a77f 100644
--- a/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml
+++ b/car_product/car_ui_portrait/overlay/frameworks/base/core/res/res/values/dimens.xml
@@ -18,6 +18,6 @@
     <!-- Height of the status bar -->
     <dimen name="status_bar_height">92dp</dimen>
     <!-- Height of the bottom navigation / climate bar. -->
-    <dimen name="navigation_bar_height">136dp</dimen>
-    <dimen name="navigation_bar_height_landscape">136dp</dimen>
+    <dimen name="navigation_bar_height">160dp</dimen>
+    <dimen name="navigation_bar_height_landscape">160dp</dimen>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
index ff625cf..051115c 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/Android.bp
@@ -22,4 +22,9 @@
         "--no-resource-deduping",
         "--no-resource-removal"
     ],
+    static_libs: [
+        "androidx.cardview_cardview",
+        "car-media-common",
+        "car-apps-common",
+    ],
 }
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml
new file mode 100644
index 0000000..fbd91ba
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_only.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<!-- Layout for a DescriptiveTextView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="horizontal">
+
+    <include layout="@layout/descriptive_text"
+             android:layout_height="match_parent"
+             android:layout_width="wrap_content"/>
+
+    <TextView
+        android:id="@+id/tap_for_more_text"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:singleLine="true"
+        android:text="Tap for more"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:visibility="gone"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml
new file mode 100644
index 0000000..7a879a1
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_descriptive_text_with_controls.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<!-- Layout for a DescriptiveTextWithControlsView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <include layout="@layout/descriptive_text"
+             android:layout_height="match_parent"
+             android:layout_width="wrap_content"/>
+
+    <LinearLayout
+        android:gravity="center"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:orientation="horizontal"
+        android:id="@+id/button_trio">
+
+    <ImageButton
+        android:id="@+id/button_left"
+        android:layout_height="@dimen/control_bar_action_icon_size"
+        android:layout_width="@dimen/control_bar_action_icon_size"
+        android:scaleType="fitCenter"/>
+
+    <ImageButton
+        android:id="@+id/button_center"
+        android:layout_height="@dimen/control_bar_action_icon_size"
+        android:layout_width="@dimen/control_bar_action_icon_size"
+        android:scaleType="fitCenter"/>
+
+    <ImageButton
+        android:id="@+id/button_right"
+        android:layout_height="@dimen/control_bar_action_icon_size"
+        android:layout_width="@dimen/control_bar_action_icon_size"
+        android:scaleType="fitCenter"/>
+    </LinearLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml
new file mode 100644
index 0000000..34fe61d
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_media.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<!-- Layout specifically for the media card, which uses media-specific playback_controls.xml -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="horizontal">
+
+    <include layout="@layout/descriptive_text"
+             android:id="@+id/media_descriptive_text"
+             android:layout_height="match_parent"
+             android:layout_width="0dp"
+             android:layout_weight="1"
+             android:layout_gravity="start|center_vertical"/>
+
+    <FrameLayout
+        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_gravity="end|center_vertical">
+
+        <com.android.car.media.common.PlaybackControlsActionBar
+            android:id="@+id/media_playback_controls_bar"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            app:columns="@integer/playback_controls_bar_columns"/>
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml
new file mode 100644
index 0000000..f08886b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_content_text_block.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<!-- Layout for a TextBlockView. Required by HomeCardFragment, but currently not used by the CarUiPortrait launcher. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/text_block"
+        android:gravity="start"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+    <TextView
+        android:id="@+id/tap_for_more_text"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:singleLine="true"
+        android:text="Tap for more"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:visibility="gone"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml
new file mode 100644
index 0000000..ccc8b80
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/card_fragment.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<androidx.cardview.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/card_view"
+    android:foreground="?android:attr/selectableItemBackground"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:visibility="gone">
+
+    <FrameLayout
+        android:id="@+id/card_background"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <!-- card_background_image is required by HomeCardFragment. Intentionally not shown by
+         setting visibility="gone" -->
+        <com.android.car.apps.common.CrossfadeImageView
+            android:id="@+id/card_background_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            android:scaleType="centerCrop"/>
+
+        <View
+            android:id="@+id/card_background_scrim"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:focusable="false"
+            android:background="@color/card_background_scrim"
+            android:alpha="@dimen/card_background_scrim_alpha"/>
+    </FrameLayout>
+
+    <RelativeLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent">
+
+        <ImageView
+            android:id="@+id/card_icon"
+            android:layout_height="@dimen/control_bar_image_size"
+            android:layout_width="@dimen/control_bar_image_size"
+            android:layout_marginStart="@dimen/card_icon_margin_start"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true"/>
+
+        <!-- Do not show -->
+        <TextView
+            android:id="@+id/card_name"
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:visibility="gone"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/card_icon"/>
+
+        <FrameLayout
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_centerVertical="true"
+            android:layout_toEndOf="@id/card_name"
+            android:layout_alignParentEnd="true"
+            android:layout_marginStart="@dimen/card_content_margin_start">
+
+            <ViewStub android:id="@+id/media_layout"
+                      android:inflatedId="@+id/media_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_media"/>
+
+            <!-- Following ViewStubs are required by the HomeCardFragment, but are currently unused
+            as the portrait launcher only shows an audio card and the respective media layout. -->
+            <ViewStub android:id="@+id/descriptive_text_layout"
+                      android:inflatedId="@+id/descriptive_text_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_descriptive_text_only"/>
+
+            <ViewStub android:id="@+id/text_block_layout"
+                      android:inflatedId="@+id/text_block_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_text_block"/>
+
+            <ViewStub android:id="@+id/descriptive_text_with_controls_layout"
+                      android:inflatedId="@+id/descriptive_text_with_controls_layout"
+                      android:layout_height="match_parent"
+                      android:layout_width="match_parent"
+                      android:visibility="gone"
+                      android:layout="@layout/card_content_descriptive_text_with_controls"/>
+
+        </FrameLayout>
+    </RelativeLayout>
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
new file mode 100644
index 0000000..156ee41
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/descriptive_text.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <!-- optional_image is required by the HomeCardFragment. Intentionally not shown by setting
+    0 height and width. -->
+    <ImageView
+        android:id="@+id/optional_image"
+        android:layout_height="0dp"
+        android:layout_width="0dp"
+        android:visibility="gone"
+        android:layout_alignParentStart="true"/>
+
+    <TextView
+        android:id="@+id/primary_text"
+        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:singleLine="true"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:layout_marginTop="@dimen/descriptive_text_vertical_margin"/>
+
+    <Chronometer
+        android:id="@+id/optional_timer"
+        android:visibility="gone"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:layout_alignParentStart="true"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
+
+    <TextView
+        android:id="@+id/optional_timer_separator"
+        android:visibility="gone"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:text="@string/ongoing_call_duration_text_separator"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:layout_toEndOf="@id/optional_timer"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
+
+    <TextView
+        android:id="@+id/secondary_text"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:singleLine="true"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="@dimen/descriptive_text_vertical_margin"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
new file mode 100644
index 0000000..0604222
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <color name="card_background_scrim">#000000</color>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml
new file mode 100644
index 0000000..976d16c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/dimens.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <dimen name="card_icon_margin_start">24dp</dimen>
+    <dimen name="card_content_margin_start">32dp</dimen>
+
+    <dimen name="descriptive_text_vertical_margin">22dp</dimen>
+
+    <dimen name="control_bar_image_size">56dp</dimen>
+
+    <dimen name="control_bar_action_icon_size">56dp</dimen>
+
+    <!-- Percent transparency of the scrim applied to the image used for the card's background as a float between 0 and 1, where 0 applies no darkening scrim-->
+    <dimen name="card_background_scrim_alpha" format="float">0.72</dimen>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
index 57e82ba..7d54116 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/integers.xml
@@ -15,6 +15,8 @@
   ~ limitations under the License.
   -->
 <resources>
+    <!-- Number of buttons shown for the media playback controls bar -->
+    <integer name="playback_controls_bar_columns">3</integer>
     <!--  Entry/exit animation transition speed in milliseconds.  This is the animation of foreground DA.-->
     <integer name="enter_exit_animation_foreground_display_area_duration_ms">500</integer>
 </resources>
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
new file mode 100644
index 0000000..2c0a471
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <string name="ongoing_call_duration_text_separator">&#160;&#8226;&#160;</string>
+</resources>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
index 6ab955d..8482e1e 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/xml/overlays.xml
@@ -15,10 +15,31 @@
   -->
 <overlay>
     <item target="id/bottom_card" value="@id/bottom_card" />
+    <item target="id/card_background" value="@id/card_background" />
+    <item target="id/card_background_image" value="@id/card_background_image" />
+    <item target="id/card_background_scrim" value="@id/card_background_scrim" />
+    <item target="id/card_icon" value="@id/card_icon" />
+    <item target="id/card_name" value="@id/card_name" />
+    <item target="id/card_view" value="@id/card_view" />
+    <item target="id/descriptive_text_layout" value="@id/descriptive_text_layout" />
+    <item target="id/text_block_layout" value="@id/text_block_layout" />
+    <item target="id/descriptive_text_with_controls_layout" value="@id/descriptive_text_with_controls_layout" />
+    <item target="id/media_descriptive_text" value="@id/media_descriptive_text" />
+    <item target="id/media_layout" value="@id/media_layout"/>
+    <item target="id/media_playback_controls_bar" value="@id/media_playback_controls_bar" />
+    <item target="id/optional_image" value="@id/optional_image" />
+    <item target="id/optional_timer" value="@id/optional_timer"/>
+    <item target="id/optional_timer_separator" value="@id/optional_timer_separator"/>
+    <item target="id/primary_text" value="@id/primary_text" />
+    <item target="id/secondary_text" value="@id/secondary_text"/>
 
+    <item target="layout/card_content_media" value="@layout/card_content_media" />
+    <item target="layout/card_fragment" value="@layout/card_fragment" />
     <item target="layout/car_launcher" value="@layout/car_launcher"/>
+    <item target="layout/descriptive_text" value="@layout/descriptive_text" />
 
     <item target="integer/enter_exit_animation_foreground_display_area_duration_ms" value="@integer/enter_exit_animation_foreground_display_area_duration_ms"/>
 
     <item target="array/config_homeCardModuleClasses" value="@array/config_homeCardModuleClasses"/>
+
 </overlay>
\ No newline at end of file
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
index e8eab9e..fa12e4f 100644
--- a/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitMediaRRO/AndroidManifest.xml
@@ -17,7 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.car.media.caruiportrait.rro">
     <application android:hasCode="false"/>
-    <overlay android:priority="10"
+    <overlay android:priority="20"
              android:targetName="CarMediaApp"
              android:targetPackage="com.android.car.media"
              android:resourcesMap="@xml/overlays"
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/Android.mk b/car_product/car_ui_portrait/rro/car-ui-customizations/Android.mk
new file mode 100644
index 0000000..a8e3b25
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2021 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+CAR_UI_RRO_SET_NAME := generatedcaruiportrait
+CAR_UI_RRO_MANIFEST_FILE := $(LOCAL_PATH)/AndroidManifest.xml
+CAR_UI_RESOURCE_DIR := $(LOCAL_PATH)/res
+CAR_UI_RRO_TARGETS := \
+    com.android.car.media \
+    com.android.car.dialer \
+
+include packages/apps/Car/libs/car-ui-lib/generate_rros.mk
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
new file mode 100644
index 0000000..9d3a1a4
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="{{RRO_PACKAGE_NAME}}">
+    <application android:hasCode="false"/>
+    <overlay android:priority="10"
+             android:targetName="car-ui-lib"
+             android:targetPackage="{{TARGET_PACKAGE_NAME}}"
+             android:resourcesMap="@xml/overlays"
+             android:isStatic="true"
+             android:requiredSystemPropertyName="ro.build.characteristics"
+             android:requiredSystemPropertyValue="automotive"/>
+</manifest>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk b/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
new file mode 100644
index 0000000..a4c86bd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/product.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2021 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.
+#
+
+# Inherit from this product to include the "Car Ui Portrait" RROs for CarUi
+# Include generated RROs
+PRODUCT_PACKAGES += \
+    generatedcaruiportrait-com-android-car-media \
+    generatedcaruiportrait-com-android-car-dialer \
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_primary.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_primary.xml
new file mode 100644
index 0000000..860f219
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_primary.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 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.
+-->
+<!-- Copy of ?android:attr/textColorPrimary (frameworks/base/res/res/color/text_color_primary.xml)
+     but with a ux restricted state. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item app:state_ux_restricted="true"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item android:color="?android:attr/colorForeground"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_secondary.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_secondary.xml
new file mode 100644
index 0000000..f99fc86
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_text_color_secondary.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 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.
+-->
+<!-- Copy of ?android:attr/textColorSecondary (frameworks/base/res/res/color/text_color_secondary.xml)
+     but with a ux restricted state. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item app:state_ux_restricted="true"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorForeground"/>
+    <item android:color="?android:attr/colorForeground"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_toolbar_tab_item_selector.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_toolbar_tab_item_selector.xml
new file mode 100644
index 0000000..02d4374
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/car_ui_toolbar_tab_item_selector.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/car_ui_text_color_primary" android:state_activated="true"/>
+    <item android:color="@color/car_ui_text_color_secondary"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
new file mode 100644
index 0000000..4412c36
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/color/tab_side_indicator_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#4285F4" android:state_activated="true"/>
+    <item android:color="@android:color/transparent"/>
+</selector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_down.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_down.xml
new file mode 100644
index 0000000..e2d1b93
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_down.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M14.83,16.42L24,25.59l9.17,-9.17L36,19.25l-12,12 -12,-12z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_up.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_up.xml
new file mode 100644
index 0000000..c8cc84f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_ic_up.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M14.83,30.83L24,21.66l9.17,9.17L36,28 24,16 12,28z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_scrollbar_thumb.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_scrollbar_thumb.xml
new file mode 100644
index 0000000..54922cf
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_recyclerview_scrollbar_thumb.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#99000000" />
+    <corners android:radius="100dp"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_divider.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_divider.xml
new file mode 100644
index 0000000..9b47736
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  ~
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <size android:width="16dp"/>
+</shape>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_ripple.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_ripple.xml
new file mode 100644
index 0000000..9ac2a1f
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/drawable/car_ui_toolbar_menu_item_icon_ripple.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  ~
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="#27ffffff"
+        android:radius="48dp"/>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
new file mode 100644
index 0000000..5aa301b
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_base_layout_toolbar.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+<!-- This is for the two-row version of the toolbar -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:tag="CarUiBaseLayoutToolbar">
+
+    <!-- When not in touch mode, if we clear focus in current window, Android will re-focus the
+         first focusable view in the window automatically. Adding a FocusParkingView to the window
+         can fix this issue, because it can take focus, and it is transparent and its default focus
+         highlight is disabled, so it's invisible to the user no matter whether it's focused or not.
+         -->
+    <com.android.car.ui.FocusParkingView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <FrameLayout
+        android:id="@+id/car_ui_base_layout_content_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toEndOf="@id/left_part_of_toolbar_focus_area"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+    <com.android.car.ui.FocusArea
+        android:id="@+id/top_part_of_toolbar_focus_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:layout_width="match_parent"
+            android:layout_height="90dp"
+            android:background="?android:attr/colorBackground"
+            android:tag="car_ui_top_inset"
+            app:layout_constraintTop_toTopOf="parent">
+            <com.android.car.ui.baselayout.ClickBlockingView
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintBottom_toBottomOf="parent"/>
+
+            <FrameLayout
+                android:id="@+id/car_ui_toolbar_nav_icon_container"
+                android:layout_width="90dp"
+                android:layout_height="0dp"
+                android:layout_marginStart="88dp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent">
+
+                <ImageView
+                    android:id="@+id/car_ui_toolbar_nav_icon"
+                    android:layout_width="@dimen/car_ui_toolbar_nav_icon_size"
+                    android:layout_height="@dimen/car_ui_toolbar_nav_icon_size"
+                    android:layout_gravity="center"
+                    android:scaleType="fitXY"
+                    android:background="@drawable/car_ui_toolbar_menu_item_icon_ripple"
+                    android:tint="@color/car_ui_text_color_primary"/>
+
+                <ImageView
+                    android:id="@+id/car_ui_toolbar_logo"
+                    android:layout_width="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_height="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_gravity="center"
+                    android:scaleType="fitXY" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/car_ui_toolbar_title_logo_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/car_ui_toolbar_title_container"
+                app:layout_constraintHorizontal_chainStyle="packed">
+
+                <ImageView
+                    android:id="@+id/car_ui_toolbar_title_logo"
+                    android:layout_width="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_height="@dimen/car_ui_toolbar_logo_size"
+                    android:layout_gravity="center"
+                    android:scaleType="fitXY" />
+            </FrameLayout>
+
+            <LinearLayout android:layout_height="wrap_content"
+                          android:layout_width="wrap_content"
+                          android:id="@+id/car_ui_toolbar_title_container"
+                          android:orientation="vertical"
+                          android:layout_marginStart="16dp"
+                          app:layout_goneMarginStart="0dp"
+                          app:layout_constraintBottom_toBottomOf="parent"
+                          app:layout_constraintTop_toTopOf="parent"
+                          app:layout_constraintEnd_toEndOf="parent"
+                          app:layout_constraintStart_toEndOf="@id/car_ui_toolbar_title_logo_container">
+                <TextView android:id="@+id/car_ui_toolbar_title"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:singleLine="true"
+                          android:textAlignment="viewStart"
+                          android:textAppearance="@style/TextAppearance.CarUi.Widget.Toolbar.Title"/>
+                <TextView android:id="@+id/car_ui_toolbar_subtitle"
+                          android:layout_width="wrap_content"
+                          android:layout_height="wrap_content"
+                          android:visibility="gone"
+                          android:textAlignment="viewStart"
+                          android:textAppearance="?android:attr/textAppearanceSmall"/>
+            </LinearLayout>
+
+            <FrameLayout
+                android:id="@+id/car_ui_toolbar_search_view_container"
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@+id/car_ui_toolbar_menu_items_container"
+                app:layout_constraintStart_toEndOf="@+id/car_ui_toolbar_nav_icon_container"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <LinearLayout
+                android:id="@+id/car_ui_toolbar_menu_items_container"
+                android:divider="@drawable/car_ui_toolbar_menu_item_divider"
+                android:showDividers="beginning|middle|end"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:orientation="horizontal"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <ProgressBar
+                android:id="@+id/car_ui_toolbar_progress_bar"
+                style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:indeterminate="true"
+                android:visibility="gone"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent" />
+
+            <!-- Hairline across bottom of toolbar -->
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="2dp"
+                android:background="#F1F3F4"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </com.android.car.ui.FocusArea>
+
+    <com.android.car.ui.FocusArea
+        android:id="@+id/left_part_of_toolbar_focus_area"
+        android:layout_width="wrap_content"
+        android:layout_height="0dp"
+        android:tag="car_ui_left_inset"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/top_part_of_toolbar_focus_area"
+        app:layout_constraintBottom_toBottomOf="parent">
+
+        <com.android.car.ui.toolbar.TabLayout
+            android:id="@+id/car_ui_toolbar_tabs"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="vertical"/>
+    </com.android.car.ui.FocusArea>
+
+    <!-- Hairline to the right of the tabs -->
+    <View
+        android:layout_width="2dp"
+        android:layout_height="0dp"
+        android:background="#F1F3F4"
+        app:layout_constraintBottom_toBottomOf="@id/left_part_of_toolbar_focus_area"
+        app:layout_constraintTop_toTopOf="@id/left_part_of_toolbar_focus_area"
+        app:layout_constraintEnd_toEndOf="@id/left_part_of_toolbar_focus_area" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
new file mode 100644
index 0000000..7386e2c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/layout/car_ui_toolbar_tab_item.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="260dp"
+    android:layout_height="96dp"
+    android:background="?android:attr/selectableItemBackground">
+
+    <View
+        android:layout_width="6dp"
+        android:layout_height="match_parent"
+        android:background="@color/tab_side_indicator_color"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <ImageView
+        android:id="@+id/car_ui_toolbar_tab_item_icon"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:layout_marginStart="24dp"
+        android:layout_marginEnd="24dp"
+        android:scaleType="fitCenter"
+        android:tint="@color/car_ui_toolbar_tab_item_selector"
+        android:tintMode="src_in"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/car_ui_toolbar_tab_item_text"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"/>
+
+    <TextView
+        android:id="@+id/car_ui_toolbar_tab_item_text"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="24sp"
+        android:singleLine="true"
+        app:layout_constraintStart_toEndOf="@id/car_ui_toolbar_tab_item_icon"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:background="#F1F3F4"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-port/values.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-port/values.xml
new file mode 100644
index 0000000..299d726
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-port/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+<resources>
+    <bool name="car_ui_toolbar_tab_flexible_layout">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/attrs.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/attrs.xml
new file mode 100644
index 0000000..ee658e3
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/attrs.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+<resources>
+    <attr name="state_ux_restricted" format="boolean" />
+
+    <attr name="layout_constraintGuide_begin" format="dimension"/>
+    <attr name="layout_constraintGuide_end" format="dimension"/>
+    <attr name="layout_constraintGuide_percent" format="float"/>
+
+    <attr name="layout_constraintLeft_toLeftOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintLeft_toRightOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintRight_toLeftOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintRight_toRightOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintTop_toTopOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintTop_toBottomOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintBottom_toTopOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintBottom_toBottomOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintBaseline_toBaselineOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintStart_toEndOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintStart_toStartOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintEnd_toStartOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+    <attr name="layout_constraintEnd_toEndOf" format="reference|enum">
+        <enum name="parent" value="0"/>
+    </attr>
+
+    <attr name="layout_constraintHorizontal_bias" format="float"/>
+    <attr name="layout_constraintVertical_bias" format="float"/>
+
+    <attr name="layout_goneMarginLeft" format="dimension"/>
+    <attr name="layout_goneMarginTop" format="dimension"/>
+    <attr name="layout_goneMarginRight" format="dimension"/>
+    <attr name="layout_goneMarginBottom" format="dimension"/>
+    <attr name="layout_goneMarginStart" format="dimension"/>
+    <attr name="layout_goneMarginEnd" format="dimension"/>
+
+    <attr name="layout_constraintHorizontal_chainStyle" format="enum">
+        <enum name="spread" value="0"/>
+        <enum name="spread_inside" value="1"/>
+        <enum name="packed" value="2"/>
+    </attr>
+
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/drawables.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/drawables.xml
new file mode 100644
index 0000000..7bf9ad7
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/drawables.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+<resources>
+    <drawable name="car_ui_activity_background">#FDFDFD</drawable>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/values.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/values.xml
new file mode 100644
index 0000000..e68a3f8
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/values.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+<resources>
+    <bool name="car_ui_toolbar_logo_fills_nav_icon_space">false</bool>
+    <bool name="car_ui_toolbar_tab_flexible_layout">false</bool>
+    <bool name="car_ui_scrollbar_enable">false</bool>
+
+    <style name="TextAppearance.CarUi.Widget" parent="android:TextAppearance.Material.Widget">
+        <item name="android:textAlignment">viewStart</item>
+    </style>
+
+    <style name="TextAppearance.CarUi.Widget.Toolbar"/>
+
+    <style name="TextAppearance.CarUi.Widget.Toolbar.Title">
+        <item name="android:singleLine">true</item>
+        <item name="android:textSize">32sp</item>
+    </style>
+
+    <dimen name="car_ui_toolbar_logo_size">44dp</dimen>
+    <dimen name="car_ui_toolbar_nav_icon_size">44dp</dimen>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
new file mode 100644
index 0000000..9df6001
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+<overlay>
+    <item target="layout/car_ui_base_layout_toolbar" value="@layout/car_ui_base_layout_toolbar"/>
+    <item target="layout/car_ui_toolbar_tab_item" value="@layout/car_ui_toolbar_tab_item"/>
+
+    <item target="bool/car_ui_toolbar_logo_fills_nav_icon_space" value="@bool/car_ui_toolbar_logo_fills_nav_icon_space" />
+    <item target="bool/car_ui_toolbar_tab_flexible_layout" value="@bool/car_ui_toolbar_tab_flexible_layout" />
+    <item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable" />
+
+    <item target="id/car_ui_toolbar_nav_icon_container" value="@id/car_ui_toolbar_nav_icon_container" />
+    <item target="id/car_ui_toolbar_nav_icon" value="@id/car_ui_toolbar_nav_icon" />
+    <item target="id/car_ui_toolbar_logo" value="@id/car_ui_toolbar_logo" />
+    <item target="id/car_ui_toolbar_title_logo_container" value="@id/car_ui_toolbar_title_logo_container" />
+    <item target="id/car_ui_toolbar_title_logo" value="@id/car_ui_toolbar_title_logo" />
+    <item target="id/car_ui_toolbar_title" value="@id/car_ui_toolbar_title" />
+    <item target="id/car_ui_toolbar_title_container" value="@id/car_ui_toolbar_title_container" />
+    <item target="id/car_ui_toolbar_subtitle" value="@id/car_ui_toolbar_subtitle" />
+    <item target="id/car_ui_toolbar_tabs" value="@id/car_ui_toolbar_tabs" />
+    <item target="id/car_ui_toolbar_menu_items_container" value="@id/car_ui_toolbar_menu_items_container" />
+    <item target="id/car_ui_toolbar_search_view_container" value="@id/car_ui_toolbar_search_view_container" />
+    <item target="id/car_ui_toolbar_progress_bar" value="@id/car_ui_toolbar_progress_bar" />
+    <item target="id/car_ui_base_layout_content_container" value="@id/car_ui_base_layout_content_container" />
+    <item target="id/car_ui_toolbar_tab_item_icon" value="@id/car_ui_toolbar_tab_item_icon" />
+    <item target="id/car_ui_toolbar_tab_item_text" value="@id/car_ui_toolbar_tab_item_text" />
+
+    <item target="drawable/car_ui_recyclerview_ic_up" value="@drawable/car_ui_recyclerview_ic_up" />
+    <item target="drawable/car_ui_recyclerview_ic_down" value="@drawable/car_ui_recyclerview_ic_down" />
+    <item target="drawable/car_ui_recyclerview_scrollbar_thumb" value="@drawable/car_ui_recyclerview_scrollbar_thumb" />
+    <item target="drawable/car_ui_activity_background" value="@drawable/car_ui_activity_background" />
+
+    <item target="attr/state_ux_restricted" value="@attr/state_ux_restricted"/>
+    <item target="attr/layout_constraintGuide_begin" value="@attr/layout_constraintGuide_begin"/>
+    <item target="attr/layout_constraintGuide_end" value="@attr/layout_constraintGuide_end"/>
+    <item target="attr/layout_constraintStart_toStartOf" value="@attr/layout_constraintStart_toStartOf"/>
+    <item target="attr/layout_constraintStart_toEndOf" value="@attr/layout_constraintStart_toEndOf"/>
+    <item target="attr/layout_constraintEnd_toStartOf" value="@attr/layout_constraintEnd_toStartOf"/>
+    <item target="attr/layout_constraintEnd_toEndOf" value="@attr/layout_constraintEnd_toEndOf"/>
+    <item target="attr/layout_constraintLeft_toLeftOf" value="@attr/layout_constraintLeft_toLeftOf"/>
+    <item target="attr/layout_constraintLeft_toRightOf" value="@attr/layout_constraintLeft_toRightOf"/>
+    <item target="attr/layout_constraintRight_toLeftOf" value="@attr/layout_constraintRight_toLeftOf"/>
+    <item target="attr/layout_constraintRight_toRightOf" value="@attr/layout_constraintRight_toRightOf"/>
+    <item target="attr/layout_constraintTop_toTopOf" value="@attr/layout_constraintTop_toTopOf"/>
+    <item target="attr/layout_constraintTop_toBottomOf" value="@attr/layout_constraintTop_toBottomOf"/>
+    <item target="attr/layout_constraintBottom_toTopOf" value="@attr/layout_constraintBottom_toTopOf"/>
+    <item target="attr/layout_constraintBottom_toBottomOf" value="@attr/layout_constraintBottom_toBottomOf"/>
+    <item target="attr/layout_constraintHorizontal_bias" value="@attr/layout_constraintHorizontal_bias"/>
+    <item target="attr/layout_goneMarginLeft" value="@attr/layout_goneMarginLeft"/>
+    <item target="attr/layout_goneMarginRight" value="@attr/layout_goneMarginRight"/>
+    <item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/>
+    <item target="attr/layout_goneMarginBottom" value="@attr/layout_goneMarginBottom"/>
+    <item target="attr/layout_goneMarginStart" value="@attr/layout_goneMarginStart"/>
+    <item target="attr/layout_goneMarginEnd" value="@attr/layout_goneMarginEnd"/>
+    <item target="attr/layout_constraintHorizontal_chainStyle" value="@attr/layout_constraintHorizontal_chainStyle"/>
+</overlay>
diff --git a/car_product/car_ui_portrait/tools/export_emulator.py b/car_product/car_ui_portrait/tools/export_emulator.py
new file mode 100755
index 0000000..aa75f3a
--- /dev/null
+++ b/car_product/car_ui_portrait/tools/export_emulator.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+
+import subprocess
+import os
+import sys
+from shutil import copy2, copytree, rmtree
+from argparse import ArgumentParser as AP
+
+# Mostly adapted from https://cs.android.com/android/platform/superproject/+/master:device/generic/car/tools/run_local_avd.sh
+
+def fromTop(path):
+    return os.path.join(os.environ['ANDROID_BUILD_TOP'], path)
+
+def fromProductOut(path):
+    return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], path)
+
+def copyImages(outputDir, abi):
+    outputDir = os.path.join(outputDir, abi)
+    os.mkdir(outputDir)
+
+    try:
+        copy2(fromProductOut('system-qemu.img'), os.path.join(outputDir, 'system.img'))
+        copy2(fromProductOut('vendor-qemu.img'), os.path.join(outputDir, 'vendor.img'))
+        if os.path.isfile(fromProductOut('kernel-ranchu-64')):
+            copy2(fromProductOut('kernel-ranchu-64'), outputDir)
+        else:
+            copy2(fromProductOut('kernel-ranchu'), outputDir)
+        copy2(fromProductOut('ramdisk-qemu.img'), os.path.join(outputDir, 'ramdisk.img'))
+        copy2(fromProductOut('encryptionkey.img'), outputDir)
+        # take prebuilt userdata.img
+        # Ref: https://cs.android.com/android/platform/superproject/+/master:development/build/sdk.atree?q=userdata.img&ss=android%2Fplatform%2Fsuperproject:development%2Fbuild%2F
+        copy2(fromTop('device/generic/goldfish/data/etc/userdata.img'), outputDir)
+        copytree(fromProductOut('data'), os.path.join(outputDir, 'data'), dirs_exist_ok=True)
+        copy2(fromProductOut('system/build.prop'), os.path.join(outputDir, 'build.prop'))
+        copy2(fromProductOut('VerifiedBootParams.textproto'), outputDir)
+        copy2(fromProductOut('config.ini'), outputDir)
+        copy2(fromProductOut('advancedFeatures.ini'), outputDir)
+    except FileNotFoundError as f:
+        print("File not found: "+f.filename+", did you build android first?")
+        sys.exit(1)
+
+def readScreenDimens(configini):
+    width = 1080
+    height = 1920
+    density = 160
+    with open(configini, 'r') as f:
+        for line in f.readlines():
+            parts = line.split(' = ')
+            if len(parts) != 2:
+                continue
+            if parts[0] == 'hw.lcd.width':
+                width = parts[1]
+            if parts[0] == 'hw.lcd.height':
+                height = parts[1]
+    return (width, height, density)
+
+def buildAVD(outputDir, abi):
+    os.makedirs(os.path.join(outputDir, '.android/avd/my_car_avd.avd/'), exist_ok=True)
+    with open(os.path.join(outputDir, '.android/avd/my_car_avd.ini'), 'w') as f:
+        f.write('avd.ini.encoding=UTF-8\n')
+        f.write('path=required_but_we_want_to_use_path.rel_instead\n')
+        f.write('path.rel=avd/my_car_avd.avd\n')
+
+    width, height, density = readScreenDimens(fromProductOut('config.ini'))
+
+    with open(os.path.join(outputDir, '.android/avd/my_car_avd.avd/config.ini'), 'w') as f:
+        f.write(f'''
+image.sysdir.1 = unused_because_passing_-sysdir_to_emulator
+hw.lcd.density = {density}
+hw.lcd.width = {width}
+hw.lcd.height = {height}
+AvdId = my_car_avd
+avd.ini.displayname = my_car_avd
+hw.ramSize = 3584
+abi.type = {abi}
+
+tag.display = Automotive
+tag.id = android-automotive
+hw.device.manufacturer = google
+hw.device.name = hawk
+avd.ini.encoding = UTF-8
+disk.dataPartition.size = 6442450944
+fastboot.chosenSnapshotFile =
+fastboot.forceChosenSnapshotBoot = no
+fastboot.forceColdBoot = no
+fastboot.forceFastBoot = yes
+hw.accelerometer = no
+hw.arc = false
+hw.audioInput = yes
+hw.battery = no
+hw.camera.back = None
+hw.camera.front = None
+hw.cpu.arch = x86_64
+hw.cpu.ncore = 4
+hw.dPad = no
+hw.device.hash2 = MD5:1fdb01985c7b4d7c19ec309cc238b0f9
+hw.gps = yes
+hw.gpu.enabled = yes
+hw.gpu.mode = auto
+hw.initialOrientation = landscape
+hw.keyboard = yes
+hw.keyboard.charmap = qwerty2
+hw.keyboard.lid = false
+hw.mainKeys = no
+hw.sdCard = no
+hw.sensors.orientation = no
+hw.sensors.proximity = no
+hw.trackBall = no
+runtime.network.latency = none
+runtime.network.speed = full
+''')
+
+def genStartScript(outputDir):
+    filepath = os.path.join(outputDir, 'start_emu.sh')
+    with open(os.open(filepath, os.O_CREAT | os.O_WRONLY, 0o750), 'w') as f:
+        f.write(f'''
+# This file is auto-generated from export_emulator.py
+OS="$(uname -s)"
+if [[ $OS == "Linux" ]]; then
+    DEFAULT_ANDROID_SDK_ROOT="$HOME/Android/Sdk"
+elif [[ $OS == "Darwin" ]]; then
+    DEFAULT_ANDROID_SDK_ROOT="/Users/$USER/Library/Android/sdk"
+else
+    echo Sorry, this does not work on $OS
+    exit
+fi
+if [[ -z $ANDROID_SDK_ROOT ]]; then
+    ANDROID_SDK_ROOT="$DEFAULT_ANDROID_SDK_ROOT"
+fi
+if ! [[ -d $ANDROID_SDK_ROOT ]]; then
+    echo Could not find android SDK root. Did you install an SDK with android studio?
+    exit
+fi
+
+# TODO: this ANDROID_EMULATOR_HOME may need to not be changed.
+# we had to change it so we could find the avd by a relative path,
+# but changing it means makes it give an "emulator is out of date"
+# warning
+
+# TODO: You shouldn't need to pass -sysdir, it should be specified
+# in the avd ini file. But I couldn't figure out how to make that work
+# with a relative path.
+
+ANDROID_EMULATOR_HOME=$(dirname $0)/.android \
+ANDROID_AVD_HOME=.android/avd \
+ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT \
+$ANDROID_SDK_ROOT/emulator/emulator \
+-avd my_car_avd -sysdir x86_64 $@
+''')
+
+
+def main():
+    parser = AP(description="Export the current build as a sharable emulator")
+    parser.add_argument('-o', '--output', default="/tmp/exported_emulator",
+                        help='Output folder. Defaults to /tmp/exported_emulator. Will wipe any existing contents!')
+    args = parser.parse_args()
+
+    if 'ANDROID_BUILD_TOP' not in os.environ or 'ANDROID_PRODUCT_OUT' not in os.environ:
+        print("Please run lunch first")
+        sys.exit(1)
+
+    if os.path.isfile(args.output):
+        print("Something already exists at "+args.output)
+        sys.exit(1)
+
+    if not os.path.isdir(os.path.dirname(args.output)):
+        print("Parent directory of "+args.output+" must already exist")
+        sys.exit(1)
+
+    rmtree(args.output, ignore_errors=True)
+    os.mkdir(args.output)
+
+    copyImages(args.output, 'x86_64')
+    buildAVD(args.output, 'x86_64')
+    genStartScript(args.output)
+    print("Done. Exported to "+args.output)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
index abf8fd2..6bd87c4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-af/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Bestuurder"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"kry benaderde ligging net op die voorgrond"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktiveer mikrofoon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
index 0f190c4..f73000b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-am/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ነጂ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ከፊት ለፊት ብቻ ግምታዊ አካባቢን ድረስ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"ማይክሮፎንን አንቃ"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
index aa51d5d..5efe621 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ar/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"السائق"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"الوصول إلى الموقع الجغرافي التقريبي في الواجهة الأمامية فقط"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"تشغيل الميكروفون"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml
index ea877d4..bd333ad 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-as/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"চালক"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"কেৱল অগ্ৰভূমিত আনুমানিক অৱস্থান এক্সেছ কৰক"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
index 3e2ccc1..65ec685 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-az/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sürücü"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"yalnız ön planda təqribi məkana daxil olun"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonu aktiv edin"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
index a20c58e..346f0e2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-b+sr+Latn/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vozač"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristup približnoj lokaciji samo u prvom planu"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogući mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
index d6e8de4..dc483db 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-be/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Вадзіцель"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"доступ да прыблізнага месцазнаходжання толькі ў асноўным рэжыме"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Уключыць мікрафон"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
index 7a2fd23..9842971 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-bg/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Шофьор"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"достъп до приблизителното местоположение само на преден план"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Активиране на микрофона"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
index e9725c8..71e7a7c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-bn/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ড্রাইভার"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"শুধুমাত্র অ্যাপটি খোলা থাকলে আপনার আনুমানিক লোকেশন অ্যাক্সেস করা"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
index a20c58e..346f0e2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-bs/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vozač"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristup približnoj lokaciji samo u prvom planu"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogući mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
index 8d24e22..e1a2044 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ca/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conductor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accedeix a la ubicació aproximada només en primer pla"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activa el micròfon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
index 2432df2..ce005f1 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-cs/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Řidič"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"přístup k přibližné poloze jen na popředí"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivovat mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
index 4f95061..1c751f9 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-da/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Chauffør"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"få kun adgang til omtrentlig placering i forgrunden"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivér mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
index 9febde6..ba314a7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-de/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Fahrer"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Nur bei Ausführung im Vordergrund auf den ungefähren Standort zugreifen"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofon aktivieren"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
index fcfe739..4eca60d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-el/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Οδηγός"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"πρόσβαση στην κατά προσέγγιση τοποθεσία μόνο στο προσκήνιο"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Ενεργοποίηση μικροφώνου"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rAU/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rCA/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rGB/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
index 85c4908..91594b0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rIN/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"access approximate location only in the foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Enable microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
index 7778984..3e208b3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-en-rXC/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‎‎Driver‎‏‎‎‏‎"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎access approximate location only in the foreground‎‏‎‎‏‎"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎Enable Microphone‎‏‎‎‏‎"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
index 5666331..ced0bde 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-es-rUS/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conductor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder a la ubicación aproximada solo en primer plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Habilitar micrófono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
index 3e3ad48..af83a18 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-es/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conductor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder a la ubicación aproximada solo al estar en primer plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Habilitar micrófono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
index 27ae02b..1876c65 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-et/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sõitja"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"juurdepääs ligikaudsele asukohale ainult esiplaanil"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Luba mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
index f7e62cf..0e06b76 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-eu/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Gidaria"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"atzitu gutxi gorabeherako kokapena aurreko planoan bakarrik"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Gaitu mikrofonoa"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
index 4d257d6..4c9f73a 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fa/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"راننده"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"دسترسی به مکان تقریبی فقط در پیش‌زمینه"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"فعال کردن میکروفن"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
index b2d5135..ce5daf3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fi/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Kuljettaja"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"käyttää likimääräistä sijaintia vain etualalla"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Laita mikrofoni päälle"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
index 2ac4be7..eb83b85 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fr-rCA/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conducteur"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accéder à votre position approximative seulement en avant-plan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activer le microphone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
index 81af986..02b7a24 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-fr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Conducteur"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"accéder à la position approximative au premier plan uniquement"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activer le micro"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
index 3754442..30b25d4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-gl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Condutor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acceder á localización aproximada só en primeiro plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activar micrófono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
index 5c6ff84..63524db 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-gu/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ડ્રાઇવર"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ફૉરગ્રાઉન્ડમાં ફક્ત અંદાજિત સ્થાન ઍક્સેસ કરો"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
index 003478d..a5ac0f3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hi/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ड्राइवर"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"अनुमानित जगह की जानकारी सिर्फ़ तब ऐक्सेस करें, जब ऐप्लिकेशन स्क्रीन पर खुला हो"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"माइक्रोफ़ोन चालू करें"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
index 4cffd31..0ac52d4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vozač"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pristupiti približnoj lokaciji samo u prednjem planu"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogući mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
index 52b7760..778f57c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hu/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sofőr"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"megközelítőleges helyadatokhoz való hozzáférés csak előtérben"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonhoz való hozzáférés engedélyezése"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
index 68df140..0dc5851 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-hy/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Վարորդ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"տեղադրության մոտավոր տվյալների հասանելիություն միայն ֆոնային ռեժիմում"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Միացնել խոսափողը"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
index 21c21a8..52cda98 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-in/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Pengemudi"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"akses perkiraan lokasi hanya saat di latar depan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktifkan Mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
index 1eb3776..b922593 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-is/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Ökumaður"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"aðgangur að áætlaðri staðsetningu aðeins í forgrunni"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Kveikja á hljóðnema"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
index c704544..10c4836 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-it/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Autista"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Accesso alla posizione approssimativa solo in primo piano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Attiva il microfono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml
index a8d3bee..657ebf2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-iw/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"נהג/ת"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"קבלת גישה למיקום משוער בחזית בלבד"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"הפעלת המיקרופון"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
index eb41c01..6da0c2c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ja/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ドライバー"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"フォアグラウンドでのみおおよその位置情報を取得"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"マイクを有効にする"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
index 4d26423..7fe766c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ka/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"მძღოლი"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"მიახლოებით მდებარეობაზე წვდომა მხოლოდ წინა პლანზე"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"მიკროფონის ჩართვა"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
index b12a6d5..36195f0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-kk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Көлік жүргізуші"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"болжалды орналасқан жер туралы ақпаратқа тек ашық экранда кіру"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Микрофонды қосу"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
index 4975540..1a74261 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-km/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"អ្នក​បើកបរ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ចូលប្រើ​ទីតាំង​ប្រហាក់ប្រហែល​តែនៅផ្ទៃ​ខាងមុខប៉ុណ្ណោះ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"បើក​មីក្រូហ្វូន"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
index 27e9a9e..e4ca9b9 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-kn/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ಡ್ರೈವರ್"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ಮುನ್ನೆಲೆಯಲ್ಲಿ ಮಾತ್ರ ಅಂದಾಜು ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
index 20facb1..52c715d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ko/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"운전자"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"포그라운드에서만 대략적인 위치에 액세스"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"마이크 사용"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
index 1a43c49..e062223 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ky/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Айдоочу"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"болжолдуу аныкталган жайгашкан жерге активдүү режимде гана кирүүгө уруксат берүү"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Микрофонду иштетүү"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
index 877a259..fabaa3d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-lo/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ຄົນຂັບລົດ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ເຂົ້າເຖິງສະຖານທີ່ໂດຍປະມານເມື່ອຢູ່ໃນພື້ນໜ້າເທົ່ານັ້ນ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"ເປີດການນຳໃຊ້ໄມໂຄຣໂຟນ"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
index 134230f..a02befb 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-lt/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vairuotojas"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"pasiekti apytikslę vietovę, tik kai programa veikia priekiniame plane"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Įgalinti mikrofoną"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
index 3cc5c88..333add2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-lv/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vadītājs"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"piekļuve aptuvenai atrašanās vietai, tikai darbojoties priekšplānā"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Iespējot mikrofonu"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
index 3b1eda7..ed49dfe 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-mk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Возач"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"пристап до приближната локација само во преден план"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Овозможи го микрофонот"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
index 7205182..a69ea5d 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ml/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ഡ്രൈവർ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ഏകദേശ ലൊക്കേഷൻ ഫോർഗ്രൗണ്ടിൽ മാത്രം ആക്‌സസ് ചെയ്യുക"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"മൈക്രോഫോൺ പ്രവർത്തനക്ഷമമാക്കുക"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
index dd1d6a2..5b3d6fb 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-mn/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Жолооч"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ойролцоо байршилд зөвхөн дэлгэц дээр хандах"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Микрофоныг идэвхжүүлэх"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
index a0619ec..ff435e0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-mr/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ड्रायव्हर"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"फक्त फोअरग्राउंडमध्ये अंदाजे स्थान अ‍ॅक्सेस करा"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
index 7f22021..6e830f7 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ms/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Pemandu"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"akses lokasi anggaran hanya di latar depan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Dayakan Mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
index aea1568..43c3d37 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-my/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ယာဉ်မောင်းသူ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"မျက်နှာစာတွင်သာ ခန့်မှန်းခြေ တည်နေရာ အသုံးပြုခြင်း"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"မိုက်ခရိုဖုန်း ဖွင့်ရန်"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
index 6e0de84..cbc2918 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-nb/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sjåfør"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"bare tilgang til omtrentlig posisjon i forgrunnen"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Slå på mikrofonen"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml
index 76ca044..7f514a6 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ne/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"चालक"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"अग्रभूमिमा मात्र अनुमानित स्थानमाथि पहुँच राख्नुहोस्"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
index 873fb01..d79cba2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-nl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Chauffeur"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"alleen toegang tot geschatte locatie op de voorgrond"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Microfoon aanzetten"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
index 964683f..939b105 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-or/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ଡ୍ରାଇଭର୍"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"କେବଳ ଫୋର୍‌ଗ୍ରାଉଣ୍ଡରେ ହାରାହାରି ଲୋକେସନ୍ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"ମାଇକ୍ରୋଫୋନକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
index 16541d3..75bbe12 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pa/strings.xml
@@ -19,4 +19,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ਡਰਾਈਵਰ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"ਸਿਰਫ਼ ਫੋਰਗ੍ਰਾਊਂਡ ਵਿੱਚ ਅਨੁਮਾਨਿਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
+    <!-- no translation found for sensor_privacy_start_use_dialog_turn_on_button (2093486820466005919) -->
+    <skip />
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
index d0ff092..32fe8a4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Kierowca"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"dostęp do przybliżonej lokalizacji tylko na pierwszym planie"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Włącz mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
index 984000a..016617e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pt-rPT/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Condutor"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"apenas aceder à localização aproximada em primeiro plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Ativar microfone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
index 7ac9eef..efca2bf 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-pt/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Motorista"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"acessar local aproximado apenas em primeiro plano"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Ativar microfone"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
index ec78db2..adf01f0 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ro/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Șofer"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"să acceseze locația aproximativă numai în prim-plan"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Activați microfonul"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
index ed49d76..12a3f43 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ru/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Водитель"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"Доступ к приблизительному местоположению только в активном режиме"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Включить"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
index fcba27e..9d75b4f 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-si/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"රියදුරු"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"පෙරබිම තුළ පමණක් ආසන්න ස්ථානයට ප්‍රවේශය"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"මයික්‍රෆෝනය සබල කරන්න"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
index c9a990d..125cb5a 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Vodič"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"prístup k približnej polohe iba v popredí"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivovať mikrofón"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
index 918dda4..52841ab 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Voznik"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"dostop do približne lokacije samo, ko deluje v ospredju"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Omogoči mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
index e4192e7..dc7bbe2 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sq/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Drejtuesi"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"qasu në vendndodhjen e përafërt vetëm në plan të parë"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivizo mikrofonin"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
index 8cce889..2cfe36e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Возач"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"приступ приближној локацији само у првом плану"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Омогући микрофон"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
index b5b4f63..1aa7c0c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sv/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Förare"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"endast åtkomst till ungefärlig plats i förgrunden"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Aktivera mikrofon"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
index 765973c..60e5469 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-sw/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Dereva"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"kufikia mahali palipokadiriwa ikiwa tu programu imefunguliwa kwenye skrini"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Washa Maikrofoni"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
index 264f0c1..38a2e03 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ta/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"கார் உரிமையாளர்"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"முன்புலத்தில் இயங்கும்போது மட்டும் தோராயமான இருப்பிடத்தைக் கண்டறிதல்"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"மைக்ரோஃபோனை இயக்கு"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml
index bf45f96..c95285e 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-te/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"డ్రైవర్"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"స్క్రీన్‌పై ఉన్నప్పుడు మాత్రమే సమీప లొకేషన్‌ను యాక్సెస్ చేయండి"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"మైక్రోఫోన్‌ను ఎనేబుల్ చేయండి"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
index 8fae2ca..6f617e3 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-th/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ผู้ขับรถ"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"เข้าถึงตำแหน่งโดยประมาณเมื่ออยู่เบื้องหน้าเท่านั้น"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"เปิดใช้ไมโครโฟน"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
index d425a87..c42b2c8 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-tl/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Driver"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"i-access lang ang tinatantyang lokasyon sa foreground"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"I-enable ang Mikropono"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
index 244564e..0a13258 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-tr/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Sürücü"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"yalnızca ön planda yaklaşık konuma erişme"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonu Etkinleştir"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
index b46d679..c15df06 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-uk/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Водій"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"отримувати доступ до даних про приблизне місцезнаходження лише в активному режимі"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Увімкнути мікрофон"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
index 89fd655..d3cea05 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-ur/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"ڈرائیور"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"صرف پیش منظر میں تخمینی مقام تک رسائی"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"مائیکروفون فعال کریں"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
index 9914c10..d15ff7c 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-uz/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Haydovchi"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"taxminiy joylashuv axborotini olishga faqat old fonda ruxsat"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Mikrofonni yoqish"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
index d478052..1e19523 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-vi/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Tài xế"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"chỉ truy cập thông tin vị trí gần đúng khi ứng dụng mở trên màn hình"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Cấp quyền truy cập micrô"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
index 06fe50d..6556c7b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"司机"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"只有在前台运行时才能获取大致位置信息"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"启用麦克风"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
index fd93b30..0d8543b 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zh-rHK/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"司機"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"只在前景存取概略位置"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"啟用麥克風"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
index 59f09e1..7340ecd 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zh-rTW/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"駕駛"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"僅可在前景中取得概略位置"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"啟用麥克風"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
index adb9402..c99c505 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values-zu/strings.xml
@@ -19,4 +19,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="owner_name" msgid="3416113395996003764">"Umshayeli"</string>
     <string name="permlab_accessCoarseLocation" msgid="2494909511737161237">"finyelela indawo enembile kuphela engaphambili"</string>
+    <string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="2093486820466005919">"Nika amandla Imakrofoni"</string>
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/strings.xml b/car_product/overlay/frameworks/base/core/res/res/values/strings.xml
index 34fd92f..eff76d4 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/strings.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/strings.xml
@@ -19,4 +19,6 @@
     <!-- Default name of the owner user [CHAR LIMIT=20] -->
     <string name="owner_name">Driver</string>
     <string name="permlab_accessCoarseLocation">access approximate location only in the foreground</string>
+    <!--- Action button in the dialog triggered if microphone is disabled but an app tried to access it. [CHAR LIMIT=60] -->
+    <string name="sensor_privacy_start_use_dialog_turn_on_button">Enable Microphone</string>
 </resources>
diff --git a/cpp/surround_view/OWNERS b/cpp/surround_view/OWNERS
deleted file mode 100644
index 2c5c8a7..0000000
--- a/cpp/surround_view/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-haoxiangl@google.com
-tanmayp@google.com
-swan@google.com
diff --git a/cpp/surround_view/app/Android.bp b/cpp/surround_view/app/Android.bp
deleted file mode 100644
index 76753d3..0000000
--- a/cpp/surround_view/app/Android.bp
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2020 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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_binary {
-    name: "sv_app",
-
-    srcs: [
-        "SurroundViewAppCommon.cpp",
-        "SurroundViewServiceCallback.cpp",
-        "shader.cpp",
-        "sv_app.cpp",
-    ],
-
-    shared_libs: [
-        "android.hardware.automotive.evs@1.1",
-        "android.hardware.automotive.sv@1.0",
-        "libEGL",
-        "libGLESv2",
-        "libbase",
-        "libbinder",
-        "libcutils",
-        "libhardware",
-        "libhidlbase",
-        "libutils",
-        "libui",
-    ],
-
-    static_libs: [
-        "libjsoncpp",
-        "libmath",
-    ],
-
-    strip: {
-        keep_symbols: true,
-    },
-
-    init_rc: ["sv_app.rc"],
-
-    cflags: [
-        "-DLOG_TAG=\"SvApp\"",
-        "-DGL_GLEXT_PROTOTYPES",
-        "-DEGL_EGLEXT_PROTOTYPES",
-        "-Wall",
-        "-Werror",
-        "-Wunused",
-        "-Wunreachable-code",
-    ],
-}
diff --git a/cpp/surround_view/app/SurroundViewAppCommon.cpp b/cpp/surround_view/app/SurroundViewAppCommon.cpp
deleted file mode 100644
index b1a2792..0000000
--- a/cpp/surround_view/app/SurroundViewAppCommon.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "SurroundViewAppCommon.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace app {
-
-bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay) {
-    LOG(INFO) << "Run 2d Surround View demo";
-
-    // Call HIDL API "start2dSession"
-    sp<ISurroundView2dSession> surroundView2dSession;
-
-    SvResult svResult;
-    pSurroundViewService->start2dSession(
-            [&surroundView2dSession, &svResult](const sp<ISurroundView2dSession>& session,
-                                                SvResult result) {
-                surroundView2dSession = session;
-                svResult = result;
-            });
-
-    if (surroundView2dSession == nullptr || svResult != SvResult::OK) {
-        LOG(ERROR) << "Failed to start2dSession";
-        return false;
-    } else {
-        LOG(INFO) << "start2dSession succeeded";
-    }
-
-    sp<SurroundViewServiceCallback> sv2dCallback =
-            new SurroundViewServiceCallback(pDisplay, surroundView2dSession);
-
-    // Start 2d stream with callback with default quality and resolution.
-    // The quality is defaulted to be HIGH_QUALITY, and the default resolution
-    // is set in the sv config file.
-    if (surroundView2dSession->startStream(sv2dCallback) != SvResult::OK) {
-        LOG(ERROR) << "Failed to start 2d stream";
-        return false;
-    }
-
-    const int kTotalViewingTimeSecs = 10;
-
-    // Let the SV algorithm run for HIGH_QUALITY until the wait time finishes
-    std::this_thread::sleep_for(std::chrono::seconds(kTotalViewingTimeSecs));
-
-    // Switch to low quality and lower resolution
-    Sv2dConfig config = {.width = kLowResolutionWidth, .blending = SvQuality::LOW};
-    if (surroundView2dSession->set2dConfig(config) != SvResult::OK) {
-        LOG(ERROR) << "Failed to set2dConfig";
-        return false;
-    }
-
-    // Let the SV algorithm run for LOW_QUALITY until the wait time finishes
-    std::this_thread::sleep_for(std::chrono::seconds(kTotalViewingTimeSecs));
-
-    // TODO(b/150412555): wait for the last frame
-    // Stop the 2d stream and session
-    surroundView2dSession->stopStream();
-
-    pSurroundViewService->stop2dSession(surroundView2dSession);
-    surroundView2dSession = nullptr;
-
-    LOG(INFO) << "SV 2D session finished.";
-
-    return true;
-};
-
-// Given a valid sv 3d session and pose, viewid and hfov parameters, sets the view.
-bool setView(sp<ISurroundView3dSession> surroundView3dSession, uint32_t viewId, uint32_t poseIndex,
-             float hfov) {
-    const View3d view3d = {
-            .viewId = viewId,
-            .pose =
-                    {
-                            .rotation = {.x = kPoseRot[poseIndex][0],
-                                         .y = kPoseRot[poseIndex][1],
-                                         .z = kPoseRot[poseIndex][2],
-                                         .w = kPoseRot[poseIndex][3]},
-                            .translation = {.x = kPoseTrans[poseIndex][0],
-                                            .y = kPoseTrans[poseIndex][1],
-                                            .z = kPoseTrans[poseIndex][2]},
-                    },
-            .horizontalFov = hfov,
-    };
-
-    const std::vector<View3d> views = {view3d};
-    if (surroundView3dSession->setViews(views) != SvResult::OK) {
-        return false;
-    }
-    return true;
-}
-
-bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay) {
-    LOG(INFO) << "Run 3d Surround View demo";
-
-    // Call HIDL API "start3dSession"
-    sp<ISurroundView3dSession> surroundView3dSession;
-
-    SvResult svResult;
-    pSurroundViewService->start3dSession(
-            [&surroundView3dSession, &svResult](const sp<ISurroundView3dSession>& session,
-                                                SvResult result) {
-                surroundView3dSession = session;
-                svResult = result;
-            });
-
-    if (surroundView3dSession == nullptr || svResult != SvResult::OK) {
-        LOG(ERROR) << "Failed to start3dSession";
-        return false;
-    } else {
-        LOG(INFO) << "start3dSession succeeded";
-    }
-
-    sp<SurroundViewServiceCallback> sv3dCallback =
-            new SurroundViewServiceCallback(pDisplay, surroundView3dSession);
-
-    // A view must be set before the 3d stream is started.
-    if (!setView(surroundView3dSession, /*viewId=*/0, /*poseIndex=*/0, kHorizontalFov)) {
-        LOG(ERROR) << "Failed to setView of pose index :" << 0;
-        return false;
-    }
-
-    // Start 3d stream with callback with default quality and resolution.
-    // The quality is defaulted to be HIGH_QUALITY, and the default resolution
-    // is set in the sv config file.
-    if (surroundView3dSession->startStream(sv3dCallback) != SvResult::OK) {
-        LOG(ERROR) << "Failed to start 3d stream";
-        return false;
-    }
-
-    // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
-    const int kTotalViewingTimeSecs = 10;
-    const std::chrono::milliseconds perPoseSleepTimeMs(kTotalViewingTimeSecs * 1000 / kPoseCount);
-    // Iterate through the pre-set views.
-    for (uint32_t i = 0; i < kPoseCount; i++) {
-        if (!setView(surroundView3dSession, /*viewId=*/i, /*poseIndex=*/i, kHorizontalFov)) {
-            LOG(WARNING) << "Failed to setView of pose index :" << i;
-        }
-        std::this_thread::sleep_for(perPoseSleepTimeMs);
-    }
-
-    // Switch to low quality and lower resolution
-    Sv3dConfig config = {.width = kLowResolutionWidth,
-                         .height = kLowResolutionHeight,
-                         .carDetails = SvQuality::LOW};
-
-    if (surroundView3dSession->set3dConfig(config) != SvResult::OK) {
-        LOG(ERROR) << "Failed to set3dConfig";
-        return false;
-    }
-
-    // Let the SV algorithm run for 10 seconds for LOW_QUALITY
-    for (uint32_t i = 0; i < kPoseCount; i++) {
-        if (!setView(surroundView3dSession, i + kPoseCount, i, kHorizontalFov)) {
-            LOG(WARNING) << "Failed to setView of pose index :" << i;
-        }
-        std::this_thread::sleep_for(perPoseSleepTimeMs);
-    }
-
-    // TODO(b/150412555): wait for the last frame
-    // Stop the 3d stream and session
-    surroundView3dSession->stopStream();
-
-    pSurroundViewService->stop3dSession(surroundView3dSession);
-    surroundView3dSession = nullptr;
-
-    LOG(DEBUG) << "SV 3D session finished.";
-
-    return true;
-};
-}  // namespace app
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/app/SurroundViewAppCommon.h b/cpp/surround_view/app/SurroundViewAppCommon.h
deleted file mode 100644
index 04e59fa..0000000
--- a/cpp/surround_view/app/SurroundViewAppCommon.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-#pragma once
-
-#include "SurroundViewServiceCallback.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
-#include <hidl/HidlTransportSupport.h>
-#include <utils/Log.h>
-#include <utils/StrongPointer.h>
-
-#include <stdio.h>
-
-#include <thread>
-
-using namespace android::hardware::automotive::sv::V1_0;
-using namespace android::hardware::automotive::evs::V1_1;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace app {
-
-const int kLowResolutionWidth = 120;
-const int kLowResolutionHeight = 90;
-
-enum DemoMode {
-    UNKNOWN,
-    DEMO_2D,
-    DEMO_3D,
-};
-
-const float kHorizontalFov = 90;
-
-// Number of views to generate.
-const uint32_t kPoseCount = 16;
-
-// Set of pose rotations expressed in quaternions.
-// Views are generated about a circle at a height about the car, point towards the center.
-const float kPoseRot[kPoseCount][4] = {{-0.251292, -0.251292, -0.660948, 0.660948},
-                                       {0.197439, 0.295488, 0.777193, -0.519304},
-                                       {0.135998, 0.328329, 0.86357, -0.357702},
-                                       {0.0693313, 0.348552, 0.916761, -0.182355},
-                                       {-7.76709e-09, 0.355381, 0.934722, 2.0429e-08},
-                                       {-0.0693313, 0.348552, 0.916761, 0.182355},
-                                       {-0.135998, 0.328329, 0.86357, 0.357702},
-                                       {-0.197439, 0.295488, 0.777193, 0.519304},
-                                       {-0.251292, 0.251292, 0.660948, 0.660948},
-                                       {-0.295488, 0.197439, 0.519304, 0.777193},
-                                       {-0.328329, 0.135998, 0.357702, 0.86357},
-                                       {-0.348552, 0.0693313, 0.182355, 0.916761},
-                                       {-0.355381, -2.11894e-09, -5.57322e-09, 0.934722},
-                                       {-0.348552, -0.0693313, -0.182355, 0.916761},
-                                       {-0.328329, -0.135998, -0.357702, 0.86357},
-                                       {-0.295488, -0.197439, -0.519304, 0.777193}};
-
-// Set of pose translations i.e. positions of the views.
-// Views are generated about a circle at a height about the car, point towards the center.
-const float kPoseTrans[kPoseCount][4] = {{4, 0, 2.5},
-                                         {3.69552, 1.53073, 2.5},
-                                         {2.82843, 2.82843, 2.5},
-                                         {1.53073, 3.69552, 2.5},
-                                         {-1.74846e-07, 4, 2.5},
-                                         {-1.53073, 3.69552, 2.5},
-                                         {-2.82843, 2.82843, 2.5},
-                                         {-3.69552, 1.53073, 2.5},
-                                         {-4, -3.49691e-07, 2.5},
-                                         {-3.69552, -1.53073, 2.5},
-                                         {-2.82843, -2.82843, 2.5},
-                                         {-1.53073, -3.69552, 2.5},
-                                         {4.76995e-08, -4, 2.5},
-                                         {1.53073, -3.69552, 2.5},
-                                         {2.82843, -2.82843, 2.5},
-                                         {3.69552, -1.53073, 2.5}};
-
-bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay);
-
-bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay);
-
-// Given a valid sv 3d session and pose, viewid and hfov parameters, sets the view.
-bool setView(sp<ISurroundView3dSession> surroundView3dSession, uint32_t viewId, uint32_t poseIndex,
-             float hfov);
-
-}  // namespace app
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/app/SurroundViewServiceCallback.cpp b/cpp/surround_view/app/SurroundViewServiceCallback.cpp
deleted file mode 100644
index a3ce519..0000000
--- a/cpp/surround_view/app/SurroundViewServiceCallback.cpp
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-#include "SurroundViewServiceCallback.h"
-
-#include <android-base/logging.h>
-#include <math/mat4.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Log.h>
-
-#include "shader_simpleTex.h"
-#include "shader.h"
-
-using android::GraphicBuffer;
-using android::hardware::automotive::evs::V1_0::DisplayState;
-using android::hardware::automotive::evs::V1_0::EvsResult;
-using android::hardware::Return;
-using android::sp;
-using std::string;
-
-EGLDisplay   SurroundViewServiceCallback::sGLDisplay;
-GLuint       SurroundViewServiceCallback::sFrameBuffer;
-GLuint       SurroundViewServiceCallback::sColorBuffer;
-GLuint       SurroundViewServiceCallback::sDepthBuffer;
-GLuint       SurroundViewServiceCallback::sTextureId;
-EGLImageKHR  SurroundViewServiceCallback::sKHRimage;
-
-const char* SurroundViewServiceCallback::getEGLError(void) {
-    switch (eglGetError()) {
-        case EGL_SUCCESS:
-            return "EGL_SUCCESS";
-        case EGL_NOT_INITIALIZED:
-            return "EGL_NOT_INITIALIZED";
-        case EGL_BAD_ACCESS:
-            return "EGL_BAD_ACCESS";
-        case EGL_BAD_ALLOC:
-            return "EGL_BAD_ALLOC";
-        case EGL_BAD_ATTRIBUTE:
-            return "EGL_BAD_ATTRIBUTE";
-        case EGL_BAD_CONTEXT:
-            return "EGL_BAD_CONTEXT";
-        case EGL_BAD_CONFIG:
-            return "EGL_BAD_CONFIG";
-        case EGL_BAD_CURRENT_SURFACE:
-            return "EGL_BAD_CURRENT_SURFACE";
-        case EGL_BAD_DISPLAY:
-            return "EGL_BAD_DISPLAY";
-        case EGL_BAD_SURFACE:
-            return "EGL_BAD_SURFACE";
-        case EGL_BAD_MATCH:
-            return "EGL_BAD_MATCH";
-        case EGL_BAD_PARAMETER:
-            return "EGL_BAD_PARAMETER";
-        case EGL_BAD_NATIVE_PIXMAP:
-            return "EGL_BAD_NATIVE_PIXMAP";
-        case EGL_BAD_NATIVE_WINDOW:
-            return "EGL_BAD_NATIVE_WINDOW";
-        case EGL_CONTEXT_LOST:
-            return "EGL_CONTEXT_LOST";
-        default:
-            return "Unknown error";
-    }
-}
-
-const string SurroundViewServiceCallback::getGLFramebufferError(void) {
-    switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
-    case GL_FRAMEBUFFER_COMPLETE:
-        return "GL_FRAMEBUFFER_COMPLETE";
-    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
-        return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
-    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
-        return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
-    case GL_FRAMEBUFFER_UNSUPPORTED:
-        return "GL_FRAMEBUFFER_UNSUPPORTED";
-    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
-        return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
-    default:
-        return std::to_string(glCheckFramebufferStatus(GL_FRAMEBUFFER));
-    }
-}
-
-bool SurroundViewServiceCallback::prepareGL() {
-    LOG(DEBUG) << __FUNCTION__;
-
-    // Just trivially return success if we're already prepared
-    if (sGLDisplay != EGL_NO_DISPLAY) {
-        return true;
-    }
-
-    // Hardcoded to RGBx output display
-    const EGLint config_attribs[] = {
-        // Tag                  Value
-        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
-        EGL_RED_SIZE,           8,
-        EGL_GREEN_SIZE,         8,
-        EGL_BLUE_SIZE,          8,
-        EGL_NONE
-    };
-
-    // Select OpenGL ES v 3
-    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
-
-    // Set up our OpenGL ES context associated with the default display
-    // (though we won't be visible)
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (display == EGL_NO_DISPLAY) {
-        LOG(ERROR) << "Failed to get egl display";
-        return false;
-    }
-
-    EGLint major = 0;
-    EGLint minor = 0;
-    if (!eglInitialize(display, &major, &minor)) {
-        LOG(ERROR) << "Failed to initialize EGL: "
-                   << getEGLError();
-        return false;
-    } else {
-        LOG(INFO) << "Initialized EGL at "
-                  << major
-                  << "."
-                  << minor;
-    }
-
-    // Select the configuration that "best" matches our desired characteristics
-    EGLConfig egl_config;
-    EGLint num_configs;
-    if (!eglChooseConfig(display, config_attribs, &egl_config, 1,
-                         &num_configs)) {
-        LOG(ERROR) << "eglChooseConfig() failed with error: "
-                   << getEGLError();
-        return false;
-    }
-
-    // Create a placeholder pbuffer so we have a surface to bind -- we never intend
-    // to draw to this because attachRenderTarget will be called first.
-    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
-    EGLSurface sPlaceholderSurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
-    if (sPlaceholderSurface == EGL_NO_SURFACE) {
-        LOG(ERROR) << "Failed to create OpenGL ES Placeholder surface: " << getEGLError();
-        return false;
-    } else {
-        LOG(INFO) << "Placeholder surface looks good!  :)";
-    }
-
-    //
-    // Create the EGL context
-    //
-    EGLContext context = eglCreateContext(display, egl_config,
-                                          EGL_NO_CONTEXT, context_attribs);
-    if (context == EGL_NO_CONTEXT) {
-        LOG(ERROR) << "Failed to create OpenGL ES Context: "
-                   << getEGLError();
-        return false;
-    }
-
-    // Activate our render target for drawing
-    if (!eglMakeCurrent(display, sPlaceholderSurface, sPlaceholderSurface, context)) {
-        LOG(ERROR) << "Failed to make the OpenGL ES Context current: "
-                   << getEGLError();
-        return false;
-    } else {
-        LOG(INFO) << "We made our context current!  :)";
-    }
-
-    // Report the extensions available on this implementation
-    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
-    LOG(INFO) << "GL EXTENSIONS:\n  "
-              << gl_extensions;
-
-    // Reserve handles for the color and depth targets we'll be setting up
-    glGenRenderbuffers(1, &sColorBuffer);
-    glGenRenderbuffers(1, &sDepthBuffer);
-
-    // Set up the frame buffer object we can modify and use for off screen
-    // rendering
-    glGenFramebuffers(1, &sFrameBuffer);
-    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
-
-    LOG(INFO) << "FrameBuffer is bound to "
-              << sFrameBuffer;
-
-    // New (from TextWrapper)
-    glGenTextures(1, &sTextureId);
-
-    // Now that we're assured success, store object handles we constructed
-    sGLDisplay = display;
-
-    GLuint mShaderProgram = 0;
-    // Load our shader program if we don't have it already
-    if (!mShaderProgram) {
-        mShaderProgram = buildShaderProgram(kVtxShaderSimpleTexture,
-                                            kPixShaderSimpleTexture,
-                                            "simpleTexture");
-        if (!mShaderProgram) {
-            LOG(ERROR) << "Error building shader program";
-            return false;
-        }
-    }
-
-    // Select our screen space simple texture shader
-    glUseProgram(mShaderProgram);
-
-    // Set up the model to clip space transform (identity matrix if we're
-    // modeling in screen space)
-    GLint loc = glGetUniformLocation(mShaderProgram, "cameraMat");
-    if (loc < 0) {
-        LOG(ERROR) << "Couldn't set shader parameter 'cameraMat'";
-    } else {
-        const android::mat4 identityMatrix;
-        glUniformMatrix4fv(loc, 1, false, identityMatrix.asArray());
-    }
-
-    GLint sampler = glGetUniformLocation(mShaderProgram, "tex");
-    if (sampler < 0) {
-        LOG(ERROR) << "Couldn't set shader parameter 'tex'";
-    } else {
-        // Tell the sampler we looked up from the shader to use texture slot 0
-        // as its source
-        glUniform1i(sampler, 0);
-    }
-
-    return true;
-}
-
-BufferDesc SurroundViewServiceCallback::convertBufferDesc(
-    const BufferDesc_1_0& src) {
-    BufferDesc dst = {};
-    AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<AHardwareBuffer_Desc *>(&dst.buffer.description);
-    pDesc->width  = src.width;
-    pDesc->height = src.height;
-    pDesc->layers = 1;
-    pDesc->format = src.format;
-    pDesc->usage  = static_cast<uint64_t>(src.usage);
-    pDesc->stride = src.stride;
-
-    dst.buffer.nativeHandle = src.memHandle;
-    dst.pixelSize = src.pixelSize;
-    dst.bufferId = src.bufferId;
-
-    return dst;
-}
-
-bool SurroundViewServiceCallback::attachRenderTarget(
-    const BufferDesc& tgtBuffer) {
-    const AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<const AHardwareBuffer_Desc *>(
-            &tgtBuffer.buffer.description);
-    // Hardcoded to RGBx for now
-    if (pDesc->format != HAL_PIXEL_FORMAT_RGBA_8888) {
-        LOG(ERROR) << "Unsupported target buffer format";
-        return false;
-    }
-
-    // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> pGfxBuffer =
-        new GraphicBuffer(tgtBuffer.buffer.nativeHandle,
-                          GraphicBuffer::CLONE_HANDLE,
-                          pDesc->width,
-                          pDesc->height,
-                          pDesc->format,
-                          pDesc->layers,
-                          GRALLOC_USAGE_HW_RENDER,
-                          pDesc->stride);
-    if (pGfxBuffer == nullptr) {
-        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
-        return false;
-    }
-
-    // Get a GL compatible reference to the graphics buffer we've been given
-    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(
-        pGfxBuffer->getNativeBuffer());
-
-    // Destroy current KHR image due to new request.
-    if (sKHRimage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(sGLDisplay, sKHRimage);
-    }
-
-    sKHRimage = eglCreateImageKHR(sGLDisplay, EGL_NO_CONTEXT,
-                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
-                                  eglImageAttributes);
-    if (sKHRimage == EGL_NO_IMAGE_KHR) {
-        LOG(ERROR) << "error creating EGLImage for target buffer: "
-                   << getEGLError();
-        return false;
-    }
-
-    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
-
-    // Construct a render buffer around the external buffer
-    glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
-    glEGLImageTargetRenderbufferStorageOES(
-        GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
-    if (eglGetError() != EGL_SUCCESS) {
-        LOG(INFO) << "glEGLImageTargetRenderbufferStorageOES => %s"
-                  << getEGLError();
-        return false;
-    }
-
-    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                              GL_RENDERBUFFER, sColorBuffer);
-    if (eglGetError() != EGL_SUCCESS) {
-        LOG(ERROR) << "glFramebufferRenderbuffer => %s", getEGLError();
-        return false;
-    }
-
-    GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-    if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
-        LOG(ERROR) << "Offscreen framebuffer not configured successfully ("
-                   << checkResult
-                   << ": "
-                   << getGLFramebufferError().c_str()
-                   << ")";
-        if (eglGetError() != EGL_SUCCESS) {
-            LOG(ERROR) << "glCheckFramebufferStatus => "
-                       << getEGLError();
-        }
-        return false;
-    }
-
-    // Set the viewport
-    glViewport(0, 0, pDesc->width, pDesc->height);
-
-    // We don't actually need the clear if we're going to cover the whole
-    // screen anyway
-    // Clear the color buffer
-    glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    return true;
-}
-
-void SurroundViewServiceCallback::detachRenderTarget() {
-    // Drop our external render target
-    if (sKHRimage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(sGLDisplay, sKHRimage);
-        sKHRimage = EGL_NO_IMAGE_KHR;
-    }
-}
-
-SurroundViewServiceCallback::SurroundViewServiceCallback(
-    sp<IEvsDisplay> pDisplay,
-    sp<ISurroundViewSession> pSession) :
-    mDisplay(pDisplay),
-    mSession(pSession) {
-    // Nothing but member initialization
-}
-
-Return<void> SurroundViewServiceCallback::notify(SvEvent svEvent) {
-    // Waiting for STREAM_STARTED event.
-    if (svEvent == SvEvent::STREAM_STARTED) {
-        LOG(INFO) << "Received STREAM_STARTED event";
-
-        // Set the display state to VISIBLE_ON_NEXT_FRAME
-        if (mDisplay != nullptr) {
-            Return<EvsResult> result =
-                mDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
-            if (result != EvsResult::OK) {
-              LOG(ERROR) << "Failed to setDisplayState";
-            }
-        } else {
-            LOG(WARNING) << "setDisplayState is ignored since EVS display"
-                         << " is null";
-        }
-
-        // Set up OpenGL (exit if fail)
-        if (!prepareGL()) {
-            LOG(ERROR) << "Error while setting up OpenGL!";
-            exit(EXIT_FAILURE);
-        }
-    } else if (svEvent == SvEvent::CONFIG_UPDATED) {
-        LOG(INFO) << "Received CONFIG_UPDATED event";
-    } else if (svEvent == SvEvent::STREAM_STOPPED) {
-        LOG(INFO) << "Received STREAM_STOPPED event";
-    } else if (svEvent == SvEvent::FRAME_DROPPED) {
-        LOG(INFO) << "Received FRAME_DROPPED event";
-    } else if (svEvent == SvEvent::TIMEOUT) {
-        LOG(INFO) << "Received TIMEOUT event";
-    } else {
-        LOG(INFO) << "Received unknown event";
-    }
-    return {};
-}
-
-Return<void> SurroundViewServiceCallback::receiveFrames(
-    const SvFramesDesc& svFramesDesc) {
-    LOG(INFO) << "Incoming frames with svBuffers size: "
-              << svFramesDesc.svBuffers.size();
-    if (svFramesDesc.svBuffers.size() == 0) {
-        return {};
-    }
-
-    // Now we assume there is only one frame for both 2d and 3d.
-    auto handle =
-          svFramesDesc.svBuffers[0].hardwareBuffer.nativeHandle
-          .getNativeHandle();
-    const AHardwareBuffer_Desc* pDesc =
-          reinterpret_cast<const AHardwareBuffer_Desc *>(
-              &svFramesDesc.svBuffers[0].hardwareBuffer.description);
-
-    LOG(INFO) << "App received frames";
-    LOG(INFO) << "descData: "
-              << pDesc->width
-              << pDesc->height
-              << pDesc->layers
-              << pDesc->format
-              << pDesc->usage
-              << pDesc->stride;
-    LOG(INFO) << "nativeHandle: "
-              << handle;
-
-    // Only process the frame when EVS display is valid. If
-    // not, ignore the coming frame.
-    if (mDisplay == nullptr) {
-        LOG(WARNING) << "Display is not ready. Skip the frame";
-    } else {
-        // Get display buffer from EVS display
-        BufferDesc_1_0 tgtBuffer = {};
-        mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
-            tgtBuffer = buff;
-        });
-
-        if (!attachRenderTarget(convertBufferDesc(tgtBuffer))) {
-            LOG(ERROR) << "Failed to attach render target";
-            return {};
-        } else {
-            LOG(INFO) << "Successfully attached render target";
-        }
-
-        // Render frame to EVS display
-        LOG(INFO) << "Rendering to display buffer";
-        sp<GraphicBuffer> graphicBuffer =
-            new GraphicBuffer(handle,
-                              GraphicBuffer::CLONE_HANDLE,
-                              pDesc->width,
-                              pDesc->height,
-                              pDesc->format,
-                              pDesc->layers,  // layer count
-                              pDesc->usage,
-                              pDesc->stride);
-
-        EGLImageKHR KHRimage = EGL_NO_IMAGE_KHR;
-
-        // Get a GL compatible reference to the graphics buffer we've been given
-        EGLint eglImageAttributes[] = {
-            EGL_IMAGE_PRESERVED_KHR,
-            EGL_TRUE,
-            EGL_NONE
-        };
-        EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(
-            graphicBuffer->getNativeBuffer());
-        KHRimage = eglCreateImageKHR(sGLDisplay, EGL_NO_CONTEXT,
-                                     EGL_NATIVE_BUFFER_ANDROID, clientBuf,
-                                     eglImageAttributes);
-        if (KHRimage == EGL_NO_IMAGE_KHR) {
-            const char *msg = getEGLError();
-            LOG(ERROR) << "error creating EGLImage: "
-                       << msg;
-            return {};
-        } else {
-            LOG(INFO) << "Successfully created EGLImage";
-
-            // Update the texture handle we already created to refer to
-            // this gralloc buffer
-            glActiveTexture(GL_TEXTURE0);
-            glBindTexture(GL_TEXTURE_2D, sTextureId);
-            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                                         static_cast<GLeglImageOES>(KHRimage));
-
-            // Initialize the sampling properties (it seems the sample may
-            // not work if this isn't done)
-            // The user of this texture may very well want to set their own
-            // filtering, but we're going to pay the (minor) price of
-            // setting this up for them to avoid the dreaded "black image"
-            // if they forget.
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                            GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                            GL_NEAREST);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
-                            GL_CLAMP_TO_EDGE);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
-                            GL_CLAMP_TO_EDGE);
-        }
-
-        // Bind the texture and assign it to the shader's sampler
-        glActiveTexture(GL_TEXTURE0);
-        glBindTexture(GL_TEXTURE_2D, sTextureId);
-
-        // We want our image to show up opaque regardless of alpha values
-        glDisable(GL_BLEND);
-
-        // Draw a rectangle on the screen
-        const GLfloat vertsCarPos[] = {
-            -1.0,  1.0, 0.0f,   // left top in window space
-            1.0,  1.0, 0.0f,    // right top
-            -1.0, -1.0, 0.0f,   // left bottom
-            1.0, -1.0, 0.0f     // right bottom
-        };
-        const GLfloat vertsCarTex[] = {
-            0.0f, 0.0f,   // left top
-            1.0f, 0.0f,   // right top
-            0.0f, 1.0f,   // left bottom
-            1.0f, 1.0f    // right bottom
-        };
-        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertsCarPos);
-        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, vertsCarTex);
-        glEnableVertexAttribArray(0);
-        glEnableVertexAttribArray(1);
-
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-        glDisableVertexAttribArray(0);
-        glDisableVertexAttribArray(1);
-
-        // Now that everything is submitted, release our hold on the
-        // texture resource
-        detachRenderTarget();
-
-        // Wait for the rendering to finish
-        glFinish();
-        detachRenderTarget();
-
-        // Drop our external render target
-        if (KHRimage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(sGLDisplay, KHRimage);
-            KHRimage = EGL_NO_IMAGE_KHR;
-        }
-
-        LOG(DEBUG) << "Rendering finished. Going to return the buffer";
-
-        // Call HIDL API "doneWithFrames" to return the ownership
-        // back to SV service
-        if (mSession == nullptr) {
-            LOG(WARNING) << "SurroundViewSession in callback is invalid";
-        } else {
-            mSession->doneWithFrames(svFramesDesc);
-        }
-
-        // Return display buffer back to EVS display
-        mDisplay->returnTargetBufferForDisplay(tgtBuffer);
-    }
-    return {};
-}
diff --git a/cpp/surround_view/app/SurroundViewServiceCallback.h b/cpp/surround_view/app/SurroundViewServiceCallback.h
deleted file mode 100644
index 467c69a..0000000
--- a/cpp/surround_view/app/SurroundViewServiceCallback.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-#pragma once
-
-#include <stdio.h>
-
-#include <utils/StrongPointer.h>
-
-#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware_buffer.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-
-using namespace android::hardware::automotive::sv::V1_0;
-using namespace android::hardware::automotive::evs::V1_1;
-
-using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-
-class SurroundViewServiceCallback : public ISurroundViewStream {
-public:
-    SurroundViewServiceCallback(android::sp<IEvsDisplay> pDisplay,
-                                android::sp<ISurroundViewSession> pSession);
-
-    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewStream.
-    android::hardware::Return<void> notify(SvEvent svEvent) override;
-    android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
-
-private:
-    static const char* getEGLError(void);
-    static const std::string getGLFramebufferError(void);
-
-    bool prepareGL();
-    BufferDesc convertBufferDesc(const BufferDesc_1_0& src);
-    bool attachRenderTarget(const BufferDesc& tgtBuffer);
-    void detachRenderTarget();
-
-    static EGLDisplay   sGLDisplay;
-    static GLuint       sFrameBuffer;
-    static GLuint       sColorBuffer;
-    static GLuint       sDepthBuffer;
-    static GLuint       sTextureId;
-    static EGLImageKHR  sKHRimage;
-
-    android::sp<IEvsDisplay> mDisplay;
-    android::sp<ISurroundViewSession> mSession;
-};
diff --git a/cpp/surround_view/app/shader.cpp b/cpp/surround_view/app/shader.cpp
deleted file mode 100644
index 3ca6f74..0000000
--- a/cpp/surround_view/app/shader.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "shader.h"
-
-#include <android-base/logging.h>
-#include <memory>
-#include <stdio.h>
-
-// Given shader source, load and compile it
-static GLuint loadShader(GLenum type, const char *shaderSrc, const char *name) {
-    // Create the shader object
-    GLuint shader = glCreateShader (type);
-    if (shader == 0) {
-        return 0;
-    }
-
-    // Load and compile the shader
-    glShaderSource(shader, 1, &shaderSrc, nullptr);
-    glCompileShader(shader);
-
-    // Verify the compilation worked as expected
-    GLint compiled = 0;
-    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
-    if (!compiled) {
-        LOG(ERROR) << "Error compiling "
-                   << (type==GL_VERTEX_SHADER ? "vtx":"pxl")
-                   << " shader for "
-                   << name;
-
-        GLint size = 0;
-        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0) {
-            // Get and report the error message
-            std::unique_ptr<char> infoLog(new char[size]);
-            glGetShaderInfoLog(shader, size, NULL, infoLog.get());
-            LOG(ERROR) << "  msg:\n"
-                       << infoLog.get();
-        }
-
-        glDeleteShader(shader);
-        return 0;
-    }
-
-    return shader;
-}
-
-
-// Create a program object given vertex and pixels shader source
-GLuint buildShaderProgram(const char* vtxSrc, const char* pxlSrc, const char* name) {
-    GLuint program = glCreateProgram();
-    if (program == 0) {
-        LOG(ERROR) << "Failed to allocate program object";
-        return 0;
-    }
-
-    // Compile the shaders and bind them to this program
-    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vtxSrc, name);
-    if (vertexShader == 0) {
-        LOG(ERROR) << "Failed to load vertex shader";
-        glDeleteProgram(program);
-        return 0;
-    }
-    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pxlSrc, name);
-    if (pixelShader == 0) {
-        LOG(ERROR) << "Failed to load pixel shader";
-        glDeleteProgram(program);
-        glDeleteShader(vertexShader);
-        return 0;
-    }
-    glAttachShader(program, vertexShader);
-    glAttachShader(program, pixelShader);
-
-    // Link the program
-    glLinkProgram(program);
-    GLint linked = 0;
-    glGetProgramiv(program, GL_LINK_STATUS, &linked);
-    if (!linked) {
-        LOG(ERROR) << "Error linking program.";
-        GLint size = 0;
-        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
-        if (size > 0) {
-            // Get and report the error message
-            std::unique_ptr<char> infoLog(new char[size]);
-            glGetProgramInfoLog(program, size, NULL, infoLog.get());
-            LOG(ERROR) << "  msg:  "
-                       << infoLog.get();
-        }
-
-        glDeleteProgram(program);
-        glDeleteShader(vertexShader);
-        glDeleteShader(pixelShader);
-        return 0;
-    }
-
-    return program;
-}
-
diff --git a/cpp/surround_view/app/shader_simpleTex.h b/cpp/surround_view/app/shader_simpleTex.h
deleted file mode 100644
index 4caf633..0000000
--- a/cpp/surround_view/app/shader_simpleTex.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SHADER_SIMPLE_TEX_H
-#define SHADER_SIMPLE_TEX_H
-
-const char kVtxShaderSimpleTexture[] = ""
-        "#version 300 es                        \n"
-        "layout(location = 0) in vec4 posCoord; \n"
-        "layout(location = 1) in vec2 texCoord; \n"
-        "uniform mat4 cameraMat;                \n"
-        "out vec2 TexCoord;                     \n"
-        "void main()                            \n"
-        "{                                      \n"
-        "   gl_Position = cameraMat * posCoord; \n"
-        "   TexCoord = texCoord;                \n"
-        "}                                      \n";
-
-const char kPixShaderSimpleTexture[] =
-        "#version 300 es                                  \n"
-        "precision mediump float;                         \n"
-        "uniform sampler2D texSampler;                    \n"
-        "in vec2 TexCoord;                                \n"
-        "out vec4 color;                                  \n"
-        "void main()                                      \n"
-        "{                                                \n"
-        "    vec4 texel = texture(texSampler, TexCoord);  \n"
-        "    color = texel;                               \n"
-        "}                                                \n";
-
-#endif // SHADER_SIMPLE_TEX_H
diff --git a/cpp/surround_view/app/sv_app.cpp b/cpp/surround_view/app/sv_app.cpp
deleted file mode 100644
index d07671d..0000000
--- a/cpp/surround_view/app/sv_app.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "SurroundViewAppCommon.h"
-#include "SurroundViewServiceCallback.h"
-
-// libhidl:
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-
-using android::sp;
-using android::hardware::Return;
-using android::hardware::automotive::evs::V1_0::EvsResult;
-
-using BufferDesc_1_0  = android::hardware::automotive::evs::V1_0::BufferDesc;
-using DisplayState = android::hardware::automotive::evs::V1_0::DisplayState;
-
-using namespace android::hardware::automotive::sv::V1_0;
-using namespace android::hardware::automotive::evs::V1_1;
-using namespace android::hardware::automotive::sv::app;
-
-// Main entry point
-int main(int argc, char** argv) {
-    // Start up
-    LOG(INFO) << "SV app starting";
-
-    DemoMode mode = UNKNOWN;
-    for (int i=1; i< argc; i++) {
-        if (strcmp(argv[i], "--use2d") == 0) {
-            mode = DEMO_2D;
-        } else if (strcmp(argv[i], "--use3d") == 0) {
-            mode = DEMO_3D;
-        } else {
-            LOG(WARNING) << "Ignoring unrecognized command line arg: "
-                         << argv[i];
-        }
-    }
-
-    if (mode == UNKNOWN) {
-        LOG(ERROR) << "No demo mode is specified. Exiting";
-        return EXIT_FAILURE;
-    }
-
-    // Set thread pool size to one to avoid concurrent events from the HAL.
-    // This pool will handle the SurroundViewStream callbacks.
-    configureRpcThreadpool(1, false /* callerWillJoin */);
-
-    // Try to connect to EVS service
-    LOG(INFO) << "Acquiring EVS Enumerator";
-    sp<IEvsEnumerator> evs = IEvsEnumerator::getService();
-    if (evs == nullptr) {
-        LOG(ERROR) << "getService(default) returned NULL.  Exiting.";
-        return EXIT_FAILURE;
-    }
-
-    // Try to connect to SV service
-    LOG(INFO) << "Acquiring SV Service";
-    android::sp<ISurroundViewService> surroundViewService
-        = ISurroundViewService::getService("default");
-
-    if (surroundViewService == nullptr) {
-        LOG(ERROR) << "getService(default) returned NULL.";
-        return EXIT_FAILURE;
-    } else {
-        LOG(INFO) << "Get ISurroundViewService default";
-    }
-
-    // Connect to evs display
-    int displayId;
-    evs->getDisplayIdList([&displayId](auto idList) {
-        displayId = idList[0];
-    });
-
-    LOG(INFO) << "Acquiring EVS Display with ID: "
-              << displayId;
-    sp<IEvsDisplay> display = evs->openDisplay_1_1(displayId);
-    if (display == nullptr) {
-        LOG(ERROR) << "EVS Display unavailable.  Exiting.";
-        return EXIT_FAILURE;
-    }
-
-    if (mode == DEMO_2D) {
-        if (!run2dSurroundView(surroundViewService, display)) {
-            LOG(ERROR) << "Something went wrong in 2d surround view demo. "
-                       << "Exiting.";
-            return EXIT_FAILURE;
-        }
-    } else if (mode == DEMO_3D) {
-        if (!run3dSurroundView(surroundViewService, display)) {
-            LOG(ERROR) << "Something went wrong in 3d surround view demo. "
-                       << "Exiting.";
-            return EXIT_FAILURE;
-        }
-    }
-
-    evs->closeDisplay(display);
-
-    LOG(DEBUG) << "SV sample app finished running successfully";
-    return EXIT_SUCCESS;
-}
diff --git a/cpp/surround_view/app/sv_app.rc b/cpp/surround_view/app/sv_app.rc
deleted file mode 100644
index 74ad768..0000000
--- a/cpp/surround_view/app/sv_app.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service sv_app /system/bin/sv_app
-    class hal
-    priority -20
-    user automotive_evs
-    group automotive_evs
-    disabled # will not automatically start with its class; must be explicitly started.
diff --git a/cpp/surround_view/sepolicy/file_contexts b/cpp/surround_view/sepolicy/file_contexts
deleted file mode 100644
index 34d2677..0000000
--- a/cpp/surround_view/sepolicy/file_contexts
+++ /dev/null
@@ -1,8 +0,0 @@
-
-###################################
-# Binaries associated with the Surround View
-#
-/system/bin/sv_app                                              u:object_r:sv_app_exec:s0
-/vendor/bin/android\.automotive\.sv\.service@1\.[0-9]+-impl     u:object_r:sv_service_impl_exec:s0
-
-###################################
diff --git a/cpp/surround_view/sepolicy/sv_app.te b/cpp/surround_view/sepolicy/sv_app.te
deleted file mode 100644
index b1aca2d..0000000
--- a/cpp/surround_view/sepolicy/sv_app.te
+++ /dev/null
@@ -1,9 +0,0 @@
-# surround view sample app
-type sv_app, domain, coredomain;
-
-# allow init to launch processes in this context
-type sv_app_exec, exec_type, file_type, system_file_type;
-init_daemon_domain(sv_app)
-
-# Allow use of binder
-binder_use(sv_app);
diff --git a/cpp/surround_view/sepolicy/sv_service_impl.te b/cpp/surround_view/sepolicy/sv_service_impl.te
deleted file mode 100644
index 2bff1f9..0000000
--- a/cpp/surround_view/sepolicy/sv_service_impl.te
+++ /dev/null
@@ -1,7 +0,0 @@
-# surround view default service implementation
-type sv_service_impl, domain;
-
-# allow init to launch processes in this context
-type sv_service_impl_exec, exec_type, file_type, vendor_file_type;
-init_daemon_domain(sv_service_impl)
-binder_use(sv_service_impl)
diff --git a/cpp/surround_view/service-impl/Android.bp b/cpp/surround_view/service-impl/Android.bp
deleted file mode 100644
index f2a4cbd..0000000
--- a/cpp/surround_view/service-impl/Android.bp
+++ /dev/null
@@ -1,463 +0,0 @@
-//
-// Copyright 2020 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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_library {
-    name : "libobj_reader",
-    vendor : true,
-    srcs: [
-        "MtlReader.cpp",
-        "ObjReader.cpp",
-    ],
-    shared_libs : [
-        "libbase",
-    ]
-}
-
-cc_test{
-    name : "obj_reader_tests",
-    test_suites : ["device-tests"],
-    vendor : true,
-    srcs : ["ObjReaderTests.cpp"],
-    shared_libs : [
-        "libobj_reader",
-        "libcutils",
-        "libbase",
-        "libutils",
-    ],
-    required: [
-        "sample_car.obj",
-        "sample_car_material.mtl",
-    ],
-}
-
-// Library for IO Module.
-cc_library {
-    name : "libio_module",
-    vendor : true,
-    srcs: [
-        "ConfigReader.cpp",
-        "CarModelConfigReader.cpp",
-        "ConfigReaderUtil.cpp",
-        "IOModule.cpp",
-    ],
-    shared_libs : [
-        "libbase",
-        "libobj_reader",
-        "libtinyxml2",
-    ]
-}
-
-cc_test{
-    name : "io_module_tests",
-    test_suites : ["device-tests"],
-    vendor : true,
-    srcs : [
-        "CarModelConfigReaderTests.cpp",
-        "ConfigReaderTests.cpp",
-    ],
-    shared_libs : [
-        "libbase",
-        "libcutils",
-        "libio_module",
-        "libobj_reader",
-        "libtinyxml2",
-        "libutils",
-    ],
-    required: [
-        "sv_sample_car_model_config.xml",
-        "sv_sample_config.xml",
-    ],
-}
-
-cc_library{
-    name : "libanimation_module",
-    vendor : true,
-    srcs : [
-        "AnimationModule.cpp",
-    ],
-    shared_libs : [
-        "android.hardware.automotive.vehicle@2.0",
-        "libbase",
-        "libhidlbase",
-        "libutils",
-    ],
-}
-
-cc_test{
-    name : "animation_module_tests",
-    test_suites : ["device-tests"],
-    vendor : true,
-    srcs : ["AnimationModuleTests.cpp"],
-    shared_libs : [
-        "android.hardware.automotive.vehicle@2.0",
-        "libanimation_module",
-        "libcutils",
-        "libbase",
-        "libhidlbase",
-        "libhardware",
-        "libutils",
-    ],
-}
-
-cc_library{
-    name : "libvhal_handler",
-    vendor : true,
-    srcs : [
-        "VhalHandler.cpp",
-    ],
-    shared_libs : [
-        "android.hardware.automotive.vehicle@2.0",
-        "android.hidl.memory@1.0",
-        "libcutils",
-        "libbase",
-        "libbinder",
-        "libhidlbase",
-        "libhardware",
-        "libhidlmemory",
-        "libui",
-        "libutils",
-    ],
-}
-
-cc_test{
-    name : "vhal_handler_tests",
-    test_suites : ["device-tests"],
-    vendor : true,
-    srcs : ["VhalHandlerTests.cpp"],
-    shared_libs : [
-        "android.hardware.automotive.vehicle@2.0",
-        "libvhal_handler",
-        "libcutils",
-        "libbase",
-        "libbinder",
-        "libhidlbase",
-        "libhardware",
-        "libhidlmemory",
-        "libui",
-        "libutils",
-    ],
-}
-
-cc_library{
-    name : "libsvsession",
-    vendor : true,
-    srcs : [
-        "CameraUtils.cpp",
-        "SurroundView2dSession.cpp",
-        "SurroundView3dSession.cpp",
-    ],
-    shared_libs : [
-        "android.hardware.automotive.evs@1.0",
-        "android.hardware.automotive.evs@1.1",
-        "android.hardware.automotive.sv@1.0",
-        "android.hardware.automotive.vehicle@2.0",
-        "android.hidl.memory@1.0",
-        "libanimation_module",
-        "libbase",
-        "libbinder",
-        "libcamera_metadata",
-        "libcore_lib_shared",
-        "libcutils",
-        "libhardware",
-        "libhidlbase",
-        "libhidlmemory",
-        "libnativewindow",
-        "libio_module",
-        "libui",
-        "libutils",
-        "libvulkan",
-        "libvhal_handler",
-    ],
-    required : [
-        "cam0.png",
-        "cam1.png",
-        "cam2.png",
-        "cam3.png",
-        "sample_car.obj",
-        "sample_car_material.mtl",
-        "sv_sample_config.xml",
-        "sv_sample_car_model_config.xml",
-    ],
-    // Disable builds except for arm64 and emulator devices
-    enabled : false,
-    arch : {
-        arm64 : {
-            enabled : true,
-        },
-        x86 : {
-            enabled : true,
-        },
-        x86_64 : {
-            enabled : true,
-        },
-    },
-}
-
-cc_test{
-    name : "sv_2d_session_tests",
-    test_suites : ["device-tests"],
-    vendor : true,
-    srcs : [
-        "SurroundView2dSessionTests.cpp",
-        "mock-evs/MockEvsCamera.cpp",
-        "mock-evs/MockEvsEnumerator.cpp",
-        "mock-evs/MockSurroundViewCallback.cpp",
-    ],
-    include_dirs: [
-        "packages/services/Car/cpp/evs/sampleDriver",
-    ],
-    shared_libs : [
-        "android.hardware.automotive.evs@1.0",
-        "android.hardware.automotive.evs@1.1",
-        "android.hardware.automotive.sv@1.0",
-        "android.hardware.automotive.vehicle@2.0",
-        "android.hidl.memory@1.0",
-        "libanimation_module",
-        "libbase",
-        "libbinder",
-        "libcamera_metadata",
-        "libcore_lib_shared",
-        "libcutils",
-        "libevsconfigmanager",
-        "libhardware",
-        "libhidlbase",
-        "libhidlmemory",
-        "libio_module",
-        "libsvsession",
-        "libtinyxml2",
-        "libui",
-        "libutils",
-        "libvhal_handler",
-    ],
-    // Disable builds except for arm64 and emulator devices
-    enabled : false,
-    arch : {
-        arm64 : {
-            enabled : true,
-        },
-        x86 : {
-            enabled : true,
-        },
-        x86_64 : {
-            enabled : true,
-        },
-    },
-    required : [
-        "sample_car.obj",
-        "sample_car_material.mtl",
-        "sv_sample_config.xml",
-        "sv_sample_car_model_config.xml",
-    ],
-}
-
-cc_test{
-    name : "sv_3d_session_tests",
-    test_suites : ["device-tests"],
-    vendor : true,
-    srcs : [
-        "SurroundView3dSessionTests.cpp",
-        "mock-evs/MockEvsCamera.cpp",
-        "mock-evs/MockEvsEnumerator.cpp",
-        "mock-evs/MockSurroundViewCallback.cpp",
-    ],
-    include_dirs: [
-        "packages/services/Car/cpp/evs/sampleDriver",
-    ],
-    shared_libs : [
-        "android.hardware.automotive.evs@1.0",
-        "android.hardware.automotive.evs@1.1",
-        "android.hardware.automotive.sv@1.0",
-        "android.hardware.automotive.vehicle@2.0",
-        "android.hidl.memory@1.0",
-        "android.hidl.allocator@1.0",
-        "libanimation_module",
-        "libbase",
-        "libbinder",
-        "libcamera_metadata",
-        "libcore_lib_shared",
-        "libcutils",
-        "libevsconfigmanager",
-        "libhardware",
-        "libhidlbase",
-        "libhidlmemory",
-        "libio_module",
-        "libsvsession",
-        "libtinyxml2",
-        "libui",
-        "libutils",
-        "libvhal_handler",
-    ],
-    // Disable builds except for arm64 and emulator devices
-    enabled : false,
-    arch : {
-        arm64 : {
-            enabled : true,
-        },
-        x86 : {
-            enabled : true,
-        },
-        x86_64 : {
-            enabled : true,
-        },
-    },
-    required : [
-        "sample_car.obj",
-        "sample_car_material.mtl",
-        "sv_sample_config.xml",
-        "sv_sample_car_model_config.xml",
-    ],
-}
-
-cc_binary{
-    name : "android.automotive.sv.service@1.0-impl",
-    vendor : true,
-    srcs : [
-        "SurroundViewService.cpp",
-        "service.cpp",
-    ],
-    init_rc : ["android.automotive.sv.service@1.0-impl.rc"],
-    shared_libs : [
-        "android.hardware.automotive.evs@1.1",
-        "android.hardware.automotive.sv@1.0",
-        "android.hardware.automotive.vehicle@2.0",
-        "android.hidl.memory@1.0",
-        "libanimation_module",
-        "libbase",
-        "libbinder",
-        "libcamera_metadata",
-        "libcore_lib_shared",
-        "libcutils",
-        "libhardware",
-        "libhidlbase",
-        "libhidlmemory",
-        "libio_module",
-        "libsvsession",
-        "libui",
-        "libutils",
-        "libvhal_handler",
-    ],
-    cflags: ["-DLOG_TAG=\"SurroundViewService\""],
-    required : [
-        "cam0.png",
-        "cam1.png",
-        "cam2.png",
-        "cam3.png",
-        "sample_car.obj",
-        "sample_car_material.mtl",
-        "sv_sample_config.xml",
-        "sv_sample_car_model_config.xml",
-    ],
-    // Disable builds except for arm64 and emulator devices
-    enabled : false,
-    arch : {
-        arm64 : {
-            enabled : true,
-        },
-        x86 : {
-            enabled : true,
-        },
-        x86_64 : {
-            enabled : true,
-        },
-    },
-    vintf_fragments : [
-        "manifest_android.hardware.automotive.sv@1.0.xml",
-    ],
-}
-
-cc_prebuilt_library_shared{
-    name : "libcore_lib_shared",
-    proprietary : true,
-    arch : {
-        arm64 : {srcs : ["lib/arm64/libcore_lib_shared.so"]},
-        x86 : {srcs : ["lib/x86/libcore_lib_shared.so"]},
-        x86_64 : {srcs : ["lib/x86-64/libcore_lib_shared.so"]},
-    },
-    shared_libs : [
-        "libutils",
-        "libcutils",
-        "libbase",
-        "libEGL",
-        "libGLESv2",
-        "libGLESv3",
-        "libc",
-        "libm",
-        "libdl",
-        "libz",
-        "liblog",
-        "libvulkan",
-    ],
-}
-
-prebuilt_etc{
-    name : "cam0.png",
-    soc_specific : true,
-    src : "test_data/0.png",
-    sub_dir : "automotive/sv",
-}
-
-prebuilt_etc{
-    name : "cam1.png",
-    soc_specific : true,
-    src : "test_data/1.png",
-    sub_dir : "automotive/sv",
-}
-
-prebuilt_etc{
-    name : "cam2.png",
-    soc_specific : true,
-    src : "test_data/2.png",
-    sub_dir : "automotive/sv",
-}
-
-prebuilt_etc {
-    name :"cam3.png",
-    soc_specific : true,
-    src : "test_data/3.png",
-    sub_dir : "automotive/sv",
-}
-
-prebuilt_etc {
-    name : "sample_car.obj",
-    soc_specific : true,
-    src : "test_data/sample_car.obj",
-    sub_dir : "automotive/sv",
-}
-
-prebuilt_etc {
-    name : "sample_car_material.mtl",
-    soc_specific : true,
-    src: "test_data/sample_car_material.mtl",
-    sub_dir: "automotive/sv",
-}
-
-prebuilt_etc {
-    name : "sv_sample_config.xml",
-    soc_specific : true,
-    src : "test_data/sv_sample_config.xml",
-    sub_dir : "automotive/sv",
-}
-
-prebuilt_etc {
-    name:"sv_sample_car_model_config.xml",
-    soc_specific : true,
-    src : "test_data/sv_sample_car_model_config.xml",
-    sub_dir : "automotive/sv",
-}
diff --git a/cpp/surround_view/service-impl/AnimationModule.cpp b/cpp/surround_view/service-impl/AnimationModule.cpp
deleted file mode 100644
index 2eecdb0..0000000
--- a/cpp/surround_view/service-impl/AnimationModule.cpp
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "AnimationModule.h"
-#include "MathHelp.h"
-
-#include <android-base/logging.h>
-#include <algorithm>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-std::array<float, 3> operator*(std::array<float, 3> lvector, float scalar) {
-    return std::array<float, 3>{
-            lvector[0] * scalar,
-            lvector[1] * scalar,
-            lvector[2] * scalar,
-    };
-}
-
-inline float getRationalNumber(const Range& mappedRange, float percentage) {
-    return mappedRange.start + (mappedRange.end - mappedRange.start) * percentage;
-}
-
-inline float getRationalNumber(const Range& mappedRange, const Range& rawRange, float rawValue) {
-    if (0 == rawRange.end - rawRange.start) {
-        return mappedRange.start;
-    }
-    const float percentage = (rawValue - rawRange.start) / (rawRange.end - rawRange.start);
-    return mappedRange.start + (mappedRange.end - mappedRange.start) * percentage > 1
-            ? 1
-            : percentage < 0 ? 0 : percentage;
-}
-
-inline uint64_t getCombinedId(const VehiclePropValue& vhalValueFloat) {
-    return static_cast<uint64_t>(vhalValueFloat.prop) << 32 | vhalValueFloat.areaId;
-}
-
-float getVhalValueFloat(const VehiclePropValue& vhalValue) {
-    int32_t type = vhalValue.prop & 0x00FF0000;
-    switch (type) {
-        case (int32_t)VehiclePropertyType::BOOLEAN:
-            return 0 == vhalValue.value.int32Values[0] ? 0.0f : 1.0f;
-        case (int32_t)VehiclePropertyType::FLOAT:
-            return vhalValue.value.floatValues[0];
-        case (int32_t)VehiclePropertyType::INT32:
-            return (float)vhalValue.value.int32Values[0];
-        case (int32_t)VehiclePropertyType::INT64:
-            return (float)vhalValue.value.int64Values[0];
-        default:
-            return 0;
-    }
-}
-}  // namespace
-
-AnimationModule::AnimationModule(const std::map<std::string, CarPart>& partsMap,
-                                 const std::map<std::string, CarTexture>& texturesMap,
-                                 const std::vector<AnimationInfo>& animations) :
-      mIsCalled(false), mPartsMap(partsMap), mTexturesMap(texturesMap), mAnimations(animations) {
-    mapVhalToParts();
-    initCarPartStatus();
-}
-
-void AnimationModule::mapVhalToParts() {
-    for (const auto& animationInfo : mAnimations) {
-        auto partId = animationInfo.partId;
-        for (const auto& gammaOp : animationInfo.gammaOpsMap) {
-            if (mVhalToPartsMap.find(gammaOp.first) != mVhalToPartsMap.end()) {
-                mVhalToPartsMap.at(gammaOp.first).insert(partId);
-            } else {
-                mVhalToPartsMap.emplace(
-                        std::make_pair(gammaOp.first, std::set<std::string>{partId}));
-            }
-        }
-        for (const auto& textureOp : animationInfo.textureOpsMap) {
-            if (mVhalToPartsMap.find(textureOp.first) != mVhalToPartsMap.end()) {
-                mVhalToPartsMap.at(textureOp.first).insert(partId);
-            } else {
-                mVhalToPartsMap.emplace(
-                        std::make_pair(textureOp.first, std::set<std::string>{partId}));
-            }
-        }
-        for (const auto& rotationOp : animationInfo.rotationOpsMap) {
-            if (mVhalToPartsMap.find(rotationOp.first) != mVhalToPartsMap.end()) {
-                mVhalToPartsMap.at(rotationOp.first).insert(partId);
-            } else {
-                mVhalToPartsMap.emplace(
-                        std::make_pair(rotationOp.first, std::set<std::string>{partId}));
-            }
-        }
-        for (const auto& translationOp : animationInfo.translationOpsMap) {
-            if (mVhalToPartsMap.find(translationOp.first) != mVhalToPartsMap.end()) {
-                mVhalToPartsMap.at(translationOp.first).insert(partId);
-            } else {
-                mVhalToPartsMap.emplace(
-                        std::make_pair(translationOp.first, std::set<std::string>{partId}));
-            }
-        }
-        mPartsToAnimationMap.emplace(std::make_pair(partId, animationInfo));
-    }
-}
-
-void AnimationModule::initCarPartStatus() {
-    for (const auto& part : mPartsMap) {
-        // Get child parts list from mPartsToAnimationMap.
-        std::vector<std::string> childIds;
-        if (mPartsToAnimationMap.find(part.first) != mPartsToAnimationMap.end()) {
-            childIds = mPartsToAnimationMap.at(part.first).childIds;
-        }
-
-        mCarPartsStatusMap.emplace(std::make_pair(part.first,
-                                                  CarPartStatus{
-                                                          .partId = part.first,
-                                                          .childIds = childIds,
-                                                          .parentModel = gMat4Identity,
-                                                          .localModel = gMat4Identity,
-                                                          .currentModel = gMat4Identity,
-                                                          .gamma = 1,
-                                                  }));
-    }
-
-    for (const auto& eachVhalToParts : mVhalToPartsMap) {
-        for (const auto& part : eachVhalToParts.second) {
-            if (mCarPartsStatusMap.at(part).vhalProgressMap.find(eachVhalToParts.first) !=
-                mCarPartsStatusMap.at(part).vhalProgressMap.end()) {
-                mCarPartsStatusMap.at(part).vhalProgressMap.at(eachVhalToParts.first) = 0.0f;
-            } else {
-                mCarPartsStatusMap.at(part).vhalProgressMap.emplace(
-                        std::make_pair(eachVhalToParts.first, 0.0f));
-            }
-            if (mCarPartsStatusMap.at(part).vhalOffMap.find(eachVhalToParts.first) !=
-                mCarPartsStatusMap.at(part).vhalOffMap.end()) {
-                mCarPartsStatusMap.at(part).vhalOffMap.at(eachVhalToParts.first) = true;
-            } else {
-                mCarPartsStatusMap.at(part).vhalOffMap.emplace(
-                        std::make_pair(eachVhalToParts.first, true));
-            }
-        }
-    }
-}
-
-// This implementation assumes the tree level is small. If tree level is large,
-// we may need to traverse the tree once and process each node(part) during
-// the reaversal.
-void AnimationModule::updateChildrenParts(const std::string& partId, const Mat4x4& parentModel) {
-    for (auto& childPart : mCarPartsStatusMap.at(partId).childIds) {
-        mCarPartsStatusMap.at(childPart).parentModel = parentModel;
-        mCarPartsStatusMap.at(childPart).currentModel =
-                appendMat(mCarPartsStatusMap.at(childPart).localModel,
-                          mCarPartsStatusMap.at(childPart).parentModel);
-        if (mUpdatedPartsMap.find(childPart) == mUpdatedPartsMap.end()) {
-            AnimationParam animationParam(childPart);
-            animationParam.SetModelMatrix(mCarPartsStatusMap.at(childPart).currentModel);
-            mUpdatedPartsMap.emplace(std::make_pair(childPart, animationParam));
-        } else {  // existing part in the map
-            mUpdatedPartsMap.at(childPart).SetModelMatrix(
-                    mCarPartsStatusMap.at(childPart).currentModel);
-        }
-        updateChildrenParts(childPart, mCarPartsStatusMap.at(childPart).currentModel);
-    }
-}
-
-void AnimationModule::performGammaOp(const std::string& partId, uint64_t vhalProperty,
-                                     const GammaOp& gammaOp) {
-    CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
-    float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
-    if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {  // process off signal
-        if (currentProgress > 0) {                           // part not rest
-            if (0 == gammaOp.animationTime) {
-                currentCarPartStatus.gamma = gammaOp.gammaRange.start;
-                currentProgress = 0.0f;
-            } else {
-                const float progressDelta =
-                        (mCurrentCallTime - mLastCallTime) / gammaOp.animationTime;
-                if (progressDelta > currentProgress) {
-                    currentCarPartStatus.gamma = gammaOp.gammaRange.start;
-                    currentProgress = 0.0f;
-                } else {
-                    currentCarPartStatus.gamma =
-                            getRationalNumber(gammaOp.gammaRange, currentProgress - progressDelta);
-                    currentProgress -= progressDelta;
-                }
-            }
-        } else {
-            return;
-        }
-    } else {                               // regular signal process
-        if (0 == gammaOp.animationTime) {  // continuous value
-            currentCarPartStatus.gamma =
-                    getRationalNumber(gammaOp.gammaRange, gammaOp.vhalRange,
-                                      mVhalStatusMap.at(vhalProperty).vhalValueFloat);
-            currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
-        } else {  // non-continuous value
-            const float progressDelta = (mCurrentCallTime - mLastCallTime) / gammaOp.animationTime;
-            if (gammaOp.type == ADJUST_GAMMA_ONCE) {
-                if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
-                    currentCarPartStatus.gamma = gammaOp.gammaRange.end;
-                    currentProgress = 1.0f;
-                } else {
-                    currentCarPartStatus.gamma =
-                            getRationalNumber(gammaOp.gammaRange, currentProgress + progressDelta);
-                    currentProgress += progressDelta;
-                }
-            } else if (gammaOp.type == ADJUST_GAMMA_REPEAT) {
-                if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
-                    if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) - 1 >
-                        1) {
-                        currentCarPartStatus.gamma =
-                                currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 0.5
-                                ? gammaOp.gammaRange.start
-                                : gammaOp.gammaRange.end;
-                        currentProgress =
-                                currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 0.5 ? 0.0f
-                                                                                            : 1.0f;
-                    } else {
-                        currentCarPartStatus.gamma =
-                                getRationalNumber(gammaOp.gammaRange,
-                                                  progressDelta +
-                                                          currentCarPartStatus.vhalProgressMap.at(
-                                                                  vhalProperty) -
-                                                          1);
-                        currentProgress += progressDelta - 1;
-                    }
-                } else {
-                    currentCarPartStatus.gamma =
-                            getRationalNumber(gammaOp.gammaRange, currentProgress + progressDelta);
-                    currentProgress += progressDelta;
-                }
-            } else {
-                LOG(ERROR) << "Error type of gamma op: " << gammaOp.type;
-            }
-        }
-    }
-
-    if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
-        AnimationParam animationParam(partId);
-        animationParam.SetGamma(currentCarPartStatus.gamma);
-        mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
-    } else {  // existing part in the map
-        mUpdatedPartsMap.at(partId).SetGamma(currentCarPartStatus.gamma);
-    }
-}
-
-void AnimationModule::performTranslationOp(const std::string& partId, uint64_t vhalProperty,
-                                           const TranslationOp& translationOp) {
-    CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
-    float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
-    if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {  // process off signal
-        if (currentProgress > 0) {
-            // part not rest
-            if (0 == translationOp.animationTime) {
-                currentCarPartStatus.localModel = gMat4Identity;
-                currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
-                currentProgress = 0.0f;
-            } else {
-                const float progressDelta =
-                        (mCurrentCallTime - mLastCallTime) / translationOp.animationTime;
-                float translationUnit =
-                        getRationalNumber(translationOp.translationRange,
-                                          std::max(currentProgress - progressDelta, 0.0f));
-                currentCarPartStatus.localModel =
-                        translationMatrixToMat4x4(translationOp.direction * translationUnit);
-                currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
-                                                                 currentCarPartStatus.parentModel);
-                currentProgress = std::max(currentProgress - progressDelta, 0.0f);
-            }
-        } else {
-            return;
-        }
-    } else {  // regular signal process
-        if (translationOp.type == TRANSLATION) {
-            if (0 == translationOp.animationTime) {
-                float translationUnit =
-                        getRationalNumber(translationOp.translationRange, translationOp.vhalRange,
-                                          mVhalStatusMap.at(vhalProperty).vhalValueFloat);
-                currentCarPartStatus.localModel =
-                        translationMatrixToMat4x4(translationOp.direction * translationUnit);
-                currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
-                                                                 currentCarPartStatus.parentModel);
-                currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
-            } else {
-                float progressDelta =
-                        (mCurrentCallTime - mLastCallTime) / translationOp.animationTime;
-                if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
-                    float translationUnit = translationOp.translationRange.end;
-
-                    currentCarPartStatus.localModel =
-                            translationMatrixToMat4x4(translationOp.direction * translationUnit);
-                    currentCarPartStatus.currentModel =
-                            appendMatrix(currentCarPartStatus.localModel,
-                                         currentCarPartStatus.parentModel);
-                    currentProgress = 1.0f;
-                } else {
-                    float translationUnit = getRationalNumber(translationOp.translationRange,
-                                                              progressDelta + currentProgress);
-                    currentCarPartStatus.localModel =
-                            translationMatrixToMat4x4(translationOp.direction * translationUnit);
-                    currentCarPartStatus.currentModel =
-                            appendMatrix(currentCarPartStatus.localModel,
-                                         currentCarPartStatus.parentModel);
-                    currentProgress += progressDelta;
-                }
-            }
-        } else {
-            LOG(ERROR) << "Error type of translation op: " << translationOp.type;
-        }
-    }
-    if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
-        AnimationParam animationParam(partId);
-        animationParam.SetModelMatrix(currentCarPartStatus.currentModel);
-        mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
-    } else {  // existing part in the map
-        mUpdatedPartsMap.at(partId).SetModelMatrix(currentCarPartStatus.currentModel);
-    }
-    updateChildrenParts(partId, currentCarPartStatus.currentModel);
-}
-
-void AnimationModule::performRotationOp(const std::string& partId, uint64_t vhalProperty,
-                                        const RotationOp& rotationOp) {
-    CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
-    float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
-    if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {
-        // process off signal
-        if (currentProgress > 0) {  // part not rest
-            if (0 == rotationOp.animationTime) {
-                currentCarPartStatus.localModel = gMat4Identity;
-                currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
-                currentProgress = 0.0f;
-            } else {
-                const float progressDelta =
-                        (mCurrentCallTime - mLastCallTime) / rotationOp.animationTime;
-                if (progressDelta > currentProgress) {
-                    currentCarPartStatus.localModel = gMat4Identity;
-                    currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
-                    currentProgress = 0.0f;
-                } else {
-                    float anlgeInDegree = getRationalNumber(rotationOp.rotationRange,
-                                                            currentProgress - progressDelta);
-                    currentCarPartStatus.localModel =
-                            rotationAboutPoint(anlgeInDegree, rotationOp.axis.rotationPoint,
-                                               rotationOp.axis.axisVector);
-                    currentCarPartStatus.currentModel =
-                            appendMatrix(currentCarPartStatus.localModel,
-                                         currentCarPartStatus.parentModel);
-                    currentProgress -= progressDelta;
-                }
-            }
-        } else {
-            return;
-        }
-    } else {  // regular signal process
-        if (rotationOp.type == ROTATION_ANGLE) {
-            if (0 == rotationOp.animationTime) {
-                float angleInDegree =
-                        getRationalNumber(rotationOp.rotationRange, rotationOp.vhalRange,
-                                          mVhalStatusMap.at(vhalProperty).vhalValueFloat);
-                currentCarPartStatus.localModel =
-                        rotationAboutPoint(angleInDegree, rotationOp.axis.rotationPoint,
-                                           rotationOp.axis.axisVector);
-                currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
-                                                                 currentCarPartStatus.parentModel);
-                currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
-            } else {
-                float progressDelta = (mCurrentCallTime - mLastCallTime) / rotationOp.animationTime;
-                if (progressDelta + currentProgress > 1) {
-                    float angleInDegree = rotationOp.rotationRange.end;
-                    currentCarPartStatus.localModel =
-                            rotationAboutPoint(angleInDegree, rotationOp.axis.rotationPoint,
-                                               rotationOp.axis.axisVector);
-                    currentCarPartStatus.currentModel =
-                            appendMatrix(currentCarPartStatus.localModel,
-                                         currentCarPartStatus.parentModel);
-                    currentProgress = 1.0f;
-                } else {
-                    float anlgeInDegree = getRationalNumber(rotationOp.rotationRange,
-                                                            currentProgress + progressDelta);
-                    currentCarPartStatus.localModel =
-                            rotationAboutPoint(anlgeInDegree, rotationOp.axis.rotationPoint,
-                                               rotationOp.axis.axisVector);
-                    currentCarPartStatus.currentModel =
-                            appendMatrix(currentCarPartStatus.localModel,
-                                         currentCarPartStatus.parentModel);
-                    currentProgress += progressDelta;
-                }
-            }
-        } else if (rotationOp.type == ROTATION_SPEED) {
-            float angleDelta = (mCurrentCallTime - mLastCallTime) *
-                    getRationalNumber(rotationOp.rotationRange, rotationOp.vhalRange,
-                                      mVhalStatusMap.at(vhalProperty)
-                                              .vhalValueFloat);  // here vhalValueFloat unit is
-                                                                 // radian/ms.
-            currentCarPartStatus.localModel =
-                    appendMat(rotationAboutPoint(angleDelta, rotationOp.axis.rotationPoint,
-                                                 rotationOp.axis.axisVector),
-                              currentCarPartStatus.localModel);
-            currentCarPartStatus.currentModel =
-                    appendMatrix(currentCarPartStatus.localModel, currentCarPartStatus.parentModel);
-            currentProgress = 1.0f;
-        } else {
-            LOG(ERROR) << "Error type of rotation op: " << rotationOp.type;
-        }
-    }
-    if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
-        AnimationParam animationParam(partId);
-        animationParam.SetModelMatrix(currentCarPartStatus.currentModel);
-        mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
-    } else {  // existing part in the map
-        mUpdatedPartsMap.at(partId).SetModelMatrix(currentCarPartStatus.currentModel);
-    }
-    updateChildrenParts(partId, currentCarPartStatus.currentModel);
-}
-
-std::vector<AnimationParam> AnimationModule::getUpdatedAnimationParams(
-        const std::vector<VehiclePropValue>& vehiclePropValue) {
-    mLastCallTime = mCurrentCallTime;
-    if (!mIsCalled) {
-        mIsCalled = true;
-        mLastCallTime = (float)elapsedRealtimeNano() / 1e6;
-    }
-
-    // get current time
-    mCurrentCallTime = (float)elapsedRealtimeNano() / 1e6;
-
-    // reset mUpdatedPartsMap
-    mUpdatedPartsMap.clear();
-
-    for (const auto& vhalSignal : vehiclePropValue) {
-        // existing vhal signal
-        const uint64_t combinedId = getCombinedId(vhalSignal);
-        if (mVhalToPartsMap.find(combinedId) != mVhalToPartsMap.end()) {
-            const float valueFloat = getVhalValueFloat(vhalSignal);
-            if (mVhalStatusMap.find(combinedId) != mVhalStatusMap.end()) {
-                mVhalStatusMap.at(combinedId).vhalValueFloat = valueFloat;
-            } else {
-                mVhalStatusMap.emplace(std::make_pair(combinedId,
-                                                      VhalStatus{
-                                                              .vhalValueFloat = valueFloat,
-                                                      }));
-            }
-            bool offStatus = 0 == valueFloat;
-            for (const auto& eachPart : mVhalToPartsMap.at(combinedId)) {
-                mCarPartsStatusMap.at(eachPart).vhalOffMap.at(combinedId) = offStatus;
-            }
-        }
-    }
-
-    for (auto& vhalStatus : mVhalStatusMap) {
-        // VHAL signal not found in animation
-        uint64_t vhalProperty = vhalStatus.first;
-        if (mVhalToPartsMap.find(vhalProperty) == mVhalToPartsMap.end()) {
-            LOG(WARNING) << "VHAL " << vhalProperty << " not processed.";
-        } else {  // VHAL signal found
-            const auto& partsSet = mVhalToPartsMap.at(vhalProperty);
-            for (const auto& partId : partsSet) {
-                const auto& animationInfo = mPartsToAnimationMap.at(partId);
-                if (animationInfo.gammaOpsMap.find(vhalProperty) !=
-                    animationInfo.gammaOpsMap.end()) {
-                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for gamma op.";
-                    // TODO(b/158244276): add priority check.
-                    for (const auto& gammaOp : animationInfo.gammaOpsMap.at(vhalProperty)) {
-                        performGammaOp(partId, vhalProperty, gammaOp);
-                    }
-                }
-                if (animationInfo.textureOpsMap.find(vhalProperty) !=
-                    animationInfo.textureOpsMap.end()) {
-                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for texture op.";
-                    LOG(INFO) << "Texture op currently not supported. Skipped.";
-                    // TODO(b158244721): do texture op.
-                }
-                if (animationInfo.rotationOpsMap.find(vhalProperty) !=
-                    animationInfo.rotationOpsMap.end()) {
-                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for rotation op.";
-                    for (const auto& rotationOp : animationInfo.rotationOpsMap.at(vhalProperty)) {
-                        performRotationOp(partId, vhalProperty, rotationOp);
-                    }
-                }
-                if (animationInfo.translationOpsMap.find(vhalProperty) !=
-                    animationInfo.translationOpsMap.end()) {
-                    LOG(INFO) << "Processing VHAL " << vhalProperty << " for translation op.";
-                    for (const auto& translationOp :
-                         animationInfo.translationOpsMap.at(vhalProperty)) {
-                        performTranslationOp(partId, vhalProperty, translationOp);
-                    }
-                }
-            }
-        }
-    }
-
-    std::vector<AnimationParam> output;
-    for (auto& updatedPart : mUpdatedPartsMap) {
-        output.push_back(updatedPart.second);
-    }
-    return output;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/AnimationModule.h b/cpp/surround_view/service-impl/AnimationModule.h
deleted file mode 100644
index de8dd35..0000000
--- a/cpp/surround_view/service-impl/AnimationModule.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
-#define SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
-
-#include "IOModuleCommon.h"
-#include "core_lib.h"
-
-#include <utils/SystemClock.h>
-#include <cstdint>
-#include <map>
-#include <set>
-#include <vector>
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-
-using namespace ::android::hardware::automotive::vehicle::V2_0;
-using namespace android_auto::surround_view;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Car animation class. It is constructed with textures, animations, and
-// vhal_handler. It automatically updates animation params when
-// GetUpdatedAnimationParams() is called.
-class AnimationModule {
-public:
-    // Constructor.
-    // |parts| is from I/O module. The key value is part id.
-    // |textures| is from I/O module. The key value is texture id.
-    // |animations| is from I/O module.
-    AnimationModule(const std::map<std::string, CarPart>& partsMap,
-                    const std::map<std::string, CarTexture>& texturesMap,
-                    const std::vector<AnimationInfo>& animations);
-
-    // Gets Animation parameters with input of VehiclePropValue.
-    std::vector<AnimationParam> getUpdatedAnimationParams(
-            const std::vector<VehiclePropValue>& vehiclePropValue);
-
-private:
-    // Internal car part status.
-    struct CarPartStatus {
-        // Car part id.
-        std::string partId;
-
-        // Car part children ids.
-        std::vector<std::string> childIds;
-
-        // Parent model matrix.
-        Mat4x4 parentModel;
-
-        // Local model in local coordinate.
-        Mat4x4 localModel;
-
-        // Current status model matrix in global coordinate with
-        // animations combined.
-        // current_model = local_model * parent_model;
-        Mat4x4 currentModel;
-
-        // Gamma parameters.
-        float gamma;
-
-        // Texture id.
-        std::string textureId;
-
-        // Internal vhal percentage. Each car part maintain its own copy
-        // the vhal percentage.
-        // Key value is vhal property (combined with area id).
-        std::map<uint64_t, float> vhalProgressMap;
-
-        // Vhal off map. Key value is vhal property (combined with area id).
-        // Assume off status when vhal value is 0.
-        std::map<uint64_t, bool> vhalOffMap;
-    };
-
-    // Internal Vhal status.
-    struct VhalStatus {
-        float vhalValueFloat;
-    };
-
-    // Help function to get vhal to parts map.
-    void mapVhalToParts();
-
-    // Help function to init car part status for constructor.
-    void initCarPartStatus();
-
-    // Iteratively update children parts status if partent status is changed.
-    void updateChildrenParts(const std::string& partId, const Mat4x4& parentModel);
-
-    // Perform gamma opertion for the part with given vhal property.
-    void performGammaOp(const std::string& partId, uint64_t vhalProperty, const GammaOp& gammaOp);
-
-    // Perform translation opertion for the part with given vhal property.
-    void performTranslationOp(const std::string& partId, uint64_t vhalProperty,
-                              const TranslationOp& translationOp);
-
-    // Perform texture opertion for the part with given vhal property.
-    // Not implemented yet.
-    void performTextureOp(const std::string& partId, uint64_t vhalProperty,
-                          const TextureOp& textureOp);
-
-    // Perform rotation opertion for the part with given vhal property.
-    void performRotationOp(const std::string& partId, uint64_t vhalProperty,
-                           const RotationOp& rotationOp);
-
-    // Last call time of GetUpdatedAnimationParams() in millisecond.
-    float mLastCallTime;
-
-    // Current call time of GetUpdatedAnimationParams() in millisecond.
-    float mCurrentCallTime;
-
-    // Flag indicating if GetUpdatedAnimationParams() was called before.
-    bool mIsCalled;
-
-    std::map<std::string, CarPart> mPartsMap;
-
-    std::map<std::string, CarTexture> mTexturesMap;
-
-    std::vector<AnimationInfo> mAnimations;
-
-    std::map<std::string, AnimationInfo> mPartsToAnimationMap;
-
-    std::map<uint64_t, VhalStatus> mVhalStatusMap;
-
-    std::map<uint64_t, std::set<std::string>> mVhalToPartsMap;
-
-    std::map<std::string, CarPartStatus> mCarPartsStatusMap;
-
-    std::map<std::string, AnimationParam> mUpdatedPartsMap;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
diff --git a/cpp/surround_view/service-impl/AnimationModuleTests.cpp b/cpp/surround_view/service-impl/AnimationModuleTests.cpp
deleted file mode 100644
index 5d6e5d5..0000000
--- a/cpp/surround_view/service-impl/AnimationModuleTests.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "AnimationModuleTests"
-
-#include "AnimationModule.h"
-#include "MathHelp.h"
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include <gtest/gtest.h>
-#include <map>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-std::map<std::string, CarPart> getSampleCarPartsMap() {
-    std::vector<std::string> carFrameChildPartIds{"front_left_door", "front_right_door",
-                                                  "front_left_blinker", "front_right_blinker",
-                                                  "sun_roof"};
-
-    android_auto::surround_view::CarPart frame(std::vector<CarVertex>(),
-                                               android_auto::surround_view::CarMaterial(),
-                                               gMat4Identity, "root", carFrameChildPartIds);
-
-    android_auto::surround_view::CarPart frameChild(std::vector<CarVertex>(),
-                                                    android_auto::surround_view::CarMaterial(),
-                                                    gMat4Identity, "frame",
-                                                    std::vector<std::string>());
-
-    std::map<std::string, CarPart> sampleCarParts;
-    sampleCarParts.emplace(std::make_pair("frame", frame));
-    sampleCarParts.emplace(std::make_pair("front_left_door", frameChild));
-    sampleCarParts.emplace(std::make_pair("front_right_door", frameChild));
-    sampleCarParts.emplace(std::make_pair("front_left_blinker", frameChild));
-    sampleCarParts.emplace(std::make_pair("front_right_blinker", frameChild));
-    sampleCarParts.emplace(std::make_pair("sun_roof", frameChild));
-    return sampleCarParts;
-}
-
-std::vector<AnimationInfo> getSampleAnimations() {
-    AnimationInfo frameAnimation = AnimationInfo{
-            .partId = "frame",
-            .parentId = "root",
-            .pose = gMat4Identity,
-    };
-
-    RotationOp frontLeftDoorRotationOp =
-            RotationOp{.vhalProperty = (int64_t)(0x0200 | VehiclePropertyGroup::SYSTEM |
-                                                 VehiclePropertyType::INT32 | VehicleArea::DOOR)
-                                       << 32 |
-                               (int64_t)(VehicleArea::DOOR),
-                       .type = AnimationType::ROTATION_ANGLE,
-                       .axis =
-                               RotationAxis{
-                                       .axisVector = std::array<float, 3>{0.0f, 0.0f, 1.0f},
-                                       .rotationPoint = std::array<float, 3>{-1.0f, 0.5f, 0.0f},
-                               },
-                       .animationTime = 2000,
-                       .rotationRange =
-                               Range{
-                                       .start = 0.0f,
-                                       .end = 90.0f,
-                               },
-                       .vhalRange = Range{
-                               .start = 0.0f,
-                               .end = (float)INT32_MAX,
-                       }};
-
-    std::map<uint64_t, std::vector<RotationOp>> frontLeftDoorRotationOpsMap;
-
-    frontLeftDoorRotationOpsMap.emplace(
-            std::make_pair(frontLeftDoorRotationOp.vhalProperty,
-                           std::vector<RotationOp>{frontLeftDoorRotationOp}));
-
-    AnimationInfo frontLeftDoorAnimation = AnimationInfo{
-            .partId = "front_left_door",
-            .parentId = "frame",
-            .pose = gMat4Identity,
-            .rotationOpsMap = frontLeftDoorRotationOpsMap,
-    };
-
-    RotationOp frontRightDoorRotationOp =
-            RotationOp{.vhalProperty = (int64_t)(0x0201 | VehiclePropertyGroup::SYSTEM |
-                                                 VehiclePropertyType::INT32 | VehicleArea::DOOR)
-                                       << 32 |
-                               (int64_t)(VehicleArea::DOOR),
-                       .type = AnimationType::ROTATION_ANGLE,
-                       .axis =
-                               RotationAxis{
-                                       .axisVector = std::array<float, 3>{0.0f, 0.0f, 1.0f},
-                                       .rotationPoint = std::array<float, 3>{1.0f, 0.5f, 0.0f},
-                               },
-                       .animationTime = 2000,
-                       .rotationRange =
-                               Range{
-                                       .start = 0.0f,
-                                       .end = -90.0f,
-                               },
-                       .vhalRange = Range{
-                               .start = 0.0f,
-                               .end = (float)INT32_MAX,
-                       }};
-
-    std::map<uint64_t, std::vector<RotationOp>> frontRightDoorRotationOpsMap;
-
-    frontRightDoorRotationOpsMap.emplace(
-            std::make_pair(frontRightDoorRotationOp.vhalProperty,
-                           std::vector<RotationOp>{frontRightDoorRotationOp}));
-
-    AnimationInfo frontRightDoorAnimation = AnimationInfo{
-            .partId = "front_right_door",
-            .parentId = "frame",
-            .pose = gMat4Identity,
-            .rotationOpsMap = frontRightDoorRotationOpsMap,
-    };
-
-    GammaOp frontLeftBlinkerGammaOp = GammaOp{
-            .vhalProperty = (int64_t)(0x0300 | VehiclePropertyGroup::SYSTEM |
-                                      VehiclePropertyType::INT32 | VehicleArea::GLOBAL)
-                            << 32 |
-                    (int64_t)(VehicleArea::GLOBAL),
-            .type = AnimationType::ADJUST_GAMMA_REPEAT,
-            .animationTime = 1000,
-            .gammaRange =
-                    Range{
-                            .start = 1.0f,
-                            .end = 0.5f,
-                    },
-            .vhalRange =
-                    Range{
-                            .start = 0.0f,
-                            .end = (float)INT32_MAX,
-                    },
-    };
-
-    std::map<uint64_t, std::vector<GammaOp>> frontLeftBlinkerGammaOpsMap;
-
-    frontLeftBlinkerGammaOpsMap.emplace(
-            std::make_pair(frontLeftBlinkerGammaOp.vhalProperty,
-                           std::vector<GammaOp>{frontLeftBlinkerGammaOp}));
-
-    AnimationInfo frontLeftBlinkerAnimation = AnimationInfo{
-            .partId = "front_left_blinker",
-            .parentId = "frame",
-            .pose = gMat4Identity,
-            .gammaOpsMap = frontLeftBlinkerGammaOpsMap,
-    };
-
-    GammaOp frontRightBlinkerGammaOp = GammaOp{
-            .vhalProperty = (int64_t)(0x0301 | VehiclePropertyGroup::SYSTEM |
-                                      VehiclePropertyType::INT32 | VehicleArea::GLOBAL)
-                            << 32 |
-                    (int64_t)(VehicleArea::GLOBAL),
-            .type = AnimationType::ADJUST_GAMMA_REPEAT,
-            .animationTime = 1000,
-            .gammaRange =
-                    Range{
-                            .start = 1.0f,
-                            .end = 0.5f,
-                    },
-            .vhalRange =
-                    Range{
-                            .start = 0.0f,
-                            .end = (float)INT32_MAX,
-                    },
-    };
-
-    std::map<uint64_t, std::vector<GammaOp>> frontRightBlinkerGammaOpsMap;
-
-    frontRightBlinkerGammaOpsMap.emplace(
-            std::make_pair(frontRightBlinkerGammaOp.vhalProperty,
-                           std::vector<GammaOp>{frontRightBlinkerGammaOp}));
-
-    AnimationInfo frontRightBlinkerAnimation = AnimationInfo{
-            .partId = "front_right_blinker",
-            .parentId = "frame",
-            .pose = gMat4Identity,
-            .gammaOpsMap = frontRightBlinkerGammaOpsMap,
-    };
-
-    TranslationOp sunRoofTranslationOp = TranslationOp{
-            .vhalProperty = (int64_t)(0x0400 | VehiclePropertyGroup::SYSTEM |
-                                      VehiclePropertyType::INT32 | VehicleArea::GLOBAL)
-                            << 32 |
-                    (int64_t)(VehicleArea::GLOBAL),
-            .type = AnimationType::TRANSLATION,
-            .direction = std::array<float, 3>{0.0f, -1.0f, 0.0f},
-            .animationTime = 3000,
-            .translationRange =
-                    Range{
-                            .start = 0.0f,
-                            .end = 0.5f,
-                    },
-            .vhalRange =
-                    Range{
-                            .start = 0.0f,
-                            .end = (float)INT32_MAX,
-                    },
-    };
-
-    std::map<uint64_t, std::vector<TranslationOp>> sunRoofRotationOpsMap;
-    sunRoofRotationOpsMap.emplace(std::make_pair(sunRoofTranslationOp.vhalProperty,
-                                                 std::vector<TranslationOp>{sunRoofTranslationOp}));
-
-    AnimationInfo sunRoofAnimation = AnimationInfo{
-            .partId = "sun_roof",
-            .parentId = "frame",
-            .pose = gMat4Identity,
-            .translationOpsMap = sunRoofRotationOpsMap,
-    };
-
-    return std::vector<AnimationInfo>{frameAnimation,
-                                      frontLeftDoorAnimation,
-                                      frontRightDoorAnimation,
-                                      frontLeftBlinkerAnimation,
-                                      frontRightBlinkerAnimation,
-                                      sunRoofAnimation};
-}
-
-TEST(AnimationModuleTests, EmptyVhalSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result =
-            animationModule.getUpdatedAnimationParams(std::vector<VehiclePropValue>());
-    EXPECT_EQ(result.size(), 0);
-}
-
-TEST(AnimationModuleTests, LeftDoorAnimationOnceSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-            std::vector<VehiclePropValue>{VehiclePropValue{
-                    .areaId = (int32_t)VehicleArea::DOOR,
-                    .prop = 0x0200 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                            VehicleArea::DOOR,
-                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-            }});
-    EXPECT_EQ(result.size(), 1);
-}
-
-TEST(AnimationModuleTests, LeftDoorAnimationTenTimesSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    for (int i = 0; i < 10; ++i) {
-        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-                std::vector<VehiclePropValue>{VehiclePropValue{
-                        .areaId = (int32_t)VehicleArea::DOOR,
-                        .prop = 0x0200 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                                VehicleArea::DOOR,
-                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-                }});
-        EXPECT_EQ(result.size(), 1);
-    }
-}
-
-TEST(AnimationModuleTests, RightDoorAnimationOnceSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-            std::vector<VehiclePropValue>{VehiclePropValue{
-                    .areaId = (int32_t)VehicleArea::DOOR,
-                    .prop = 0x0201 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                            VehicleArea::DOOR,
-                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-            }});
-    EXPECT_EQ(result.size(), 1);
-}
-
-TEST(AnimationModuleTests, RightDoorAnimationTenTimesSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    for (int i = 0; i < 10; ++i) {
-        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-                std::vector<VehiclePropValue>{VehiclePropValue{
-                        .areaId = (int32_t)VehicleArea::DOOR,
-                        .prop = 0x0201 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                                VehicleArea::DOOR,
-                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-                }});
-        EXPECT_EQ(result.size(), 1);
-    }
-}
-
-TEST(AnimationModuleTests, LeftBlinkerAnimationOnceSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-            std::vector<VehiclePropValue>{VehiclePropValue{
-                    .areaId = (int32_t)VehicleArea::GLOBAL,
-                    .prop = 0x0300 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                            VehicleArea::GLOBAL,
-                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-            }});
-    EXPECT_EQ(result.size(), 1);
-}
-
-TEST(AnimationModuleTests, LeftBlinkerAnimationTenTimesSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    for (int i = 0; i < 10; ++i) {
-        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-                std::vector<VehiclePropValue>{VehiclePropValue{
-                        .areaId = (int32_t)VehicleArea::GLOBAL,
-                        .prop = 0x0300 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                                VehicleArea::GLOBAL,
-                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-                }});
-        EXPECT_EQ(result.size(), 1);
-    }
-}
-
-TEST(AnimationModuleTests, RightBlinkerAnimationOnceSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-            std::vector<VehiclePropValue>{VehiclePropValue{
-                    .areaId = (int32_t)VehicleArea::GLOBAL,
-                    .prop = 0x0301 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                            VehicleArea::GLOBAL,
-                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-            }});
-    EXPECT_EQ(result.size(), 1);
-}
-
-TEST(AnimationModuleTests, RightBlinkerAnimationTenTimesSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    for (int i = 0; i < 10; ++i) {
-        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-                std::vector<VehiclePropValue>{VehiclePropValue{
-                        .areaId = (int32_t)VehicleArea::GLOBAL,
-                        .prop = 0x0301 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                                VehicleArea::GLOBAL,
-                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-                }});
-        EXPECT_EQ(result.size(), 1);
-    }
-}
-
-TEST(AnimationModuleTests, SunRoofAnimationOnceSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-            std::vector<VehiclePropValue>{VehiclePropValue{
-                    .areaId = (int32_t)VehicleArea::GLOBAL,
-                    .prop = 0x0400 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                            VehicleArea::GLOBAL,
-                    .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-            }});
-    EXPECT_EQ(result.size(), 1);
-}
-
-TEST(AnimationModuleTests, SunRoofAnimationTenTimesSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    for (int i = 0; i < 10; ++i) {
-        std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-                std::vector<VehiclePropValue>{VehiclePropValue{
-                        .areaId = (int32_t)VehicleArea::GLOBAL,
-                        .prop = 0x0400 | VehiclePropertyGroup::SYSTEM | VehiclePropertyType::INT32 |
-                                VehicleArea::GLOBAL,
-                        .value.int32Values = std::vector<int32_t>(1, INT32_MAX),
-                }});
-        EXPECT_EQ(result.size(), 1);
-    }
-}
-
-TEST(AnimationModuleTests, All5PartsAnimationOnceSuccess) {
-    AnimationModule animationModule(getSampleCarPartsMap(), std::map<std::string, CarTexture>(),
-                                    getSampleAnimations());
-    std::vector<AnimationParam> result = animationModule.getUpdatedAnimationParams(
-            std::vector<VehiclePropValue>{VehiclePropValue{
-                                                  .areaId = (int32_t)VehicleArea::DOOR,
-                                                  .prop = 0x0200 | VehiclePropertyGroup::SYSTEM |
-                                                          VehiclePropertyType::INT32 |
-                                                          VehicleArea::DOOR,
-                                                  .value.int32Values =
-                                                          std::vector<int32_t>(1, INT32_MAX),
-                                          },
-                                          VehiclePropValue{
-                                                  .areaId = (int32_t)VehicleArea::DOOR,
-                                                  .prop = 0x0201 | VehiclePropertyGroup::SYSTEM |
-                                                          VehiclePropertyType::INT32 |
-                                                          VehicleArea::DOOR,
-                                                  .value.int32Values =
-                                                          std::vector<int32_t>(1, INT32_MAX),
-                                          },
-                                          VehiclePropValue{
-                                                  .areaId = (int32_t)VehicleArea::GLOBAL,
-                                                  .prop = 0x0300 | VehiclePropertyGroup::SYSTEM |
-                                                          VehiclePropertyType::INT32 |
-                                                          VehicleArea::GLOBAL,
-                                                  .value.int32Values =
-                                                          std::vector<int32_t>(1, INT32_MAX),
-                                          },
-                                          VehiclePropValue{
-                                                  .areaId = (int32_t)VehicleArea::GLOBAL,
-                                                  .prop = 0x0301 | VehiclePropertyGroup::SYSTEM |
-                                                          VehiclePropertyType::INT32 |
-                                                          VehicleArea::GLOBAL,
-                                                  .value.int32Values =
-                                                          std::vector<int32_t>(1, INT32_MAX),
-                                          },
-                                          VehiclePropValue{
-                                                  .areaId = (int32_t)VehicleArea::GLOBAL,
-                                                  .prop = 0x0400 | VehiclePropertyGroup::SYSTEM |
-                                                          VehiclePropertyType::INT32 |
-                                                          VehicleArea::GLOBAL,
-                                                  .value.int32Values =
-                                                          std::vector<int32_t>(1, INT32_MAX),
-                                          }});
-    EXPECT_EQ(result.size(), 5);
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/CameraUtils.cpp b/cpp/surround_view/service-impl/CameraUtils.cpp
deleted file mode 100644
index 0dd6226..0000000
--- a/cpp/surround_view/service-impl/CameraUtils.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "CameraUtils.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/automotive/evs/1.1/types.h>
-
-#include <math.h>
-
-using namespace android::hardware::automotive::evs::V1_1;
-
-using ::android::sp;
-using ::std::string;
-using ::std::vector;
-using ::std::map;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-bool isLogicalCamera(const camera_metadata_t* metadata) {
-    if (metadata == nullptr) {
-        // A logical camera device must have a valid camera metadata.
-        return false;
-    }
-
-    // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
-    camera_metadata_ro_entry_t entry;
-    int rc =
-        find_camera_metadata_ro_entry(metadata,
-                                      ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
-                                      &entry);
-    if (0 != rc) {
-        // No capabilities are found.
-        return false;
-    }
-
-    for (size_t i = 0; i < entry.count; ++i) {
-        uint8_t cap = entry.data.u8[i];
-        if (cap ==
-            ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-vector<string> getPhysicalCameraIds(sp<IEvsCamera> camera) {
-    if (camera == nullptr) {
-        LOG(WARNING) << __FUNCTION__ << "The EVS camera object is invalid";
-        return {};
-    }
-
-    CameraDesc desc;
-    camera->getCameraInfo_1_1([&desc](const CameraDesc& info) {
-        desc = info;
-    });
-
-    vector<string> physicalCameras;
-    const camera_metadata_t* metadata =
-        reinterpret_cast<camera_metadata_t*>(&desc.metadata[0]);
-
-    if (!isLogicalCamera(metadata)) {
-        // EVS assumes that the device w/o a valid metadata is a physical
-        // device.
-        LOG(INFO) << desc.v1.cameraId << " is not a logical camera device.";
-        physicalCameras.emplace_back(desc.v1.cameraId);
-        return physicalCameras;
-    }
-
-    // Look for physical camera identifiers
-    camera_metadata_ro_entry entry;
-    int rc =
-        find_camera_metadata_ro_entry(metadata,
-                                      ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
-                                      &entry);
-    if (rc != 0) {
-        LOG(ERROR) << "No physical camera ID is found for "
-                   << desc.v1.cameraId;
-        return {};
-    }
-
-    const uint8_t* ids = entry.data.u8;
-    size_t start = 0;
-    for (size_t i = 0; i < entry.count; ++i) {
-        if (ids[i] == '\0') {
-            if (start != i) {
-                string id(reinterpret_cast<const char*>(ids + start));
-                physicalCameras.emplace_back(id);
-            }
-            start = i + 1;
-        }
-    }
-
-    LOG(INFO) << desc.v1.cameraId << " consists of " << physicalCameras.size()
-              << " physical camera devices";
-    return physicalCameras;
-}
-
-string tagToString(uint32_t tag) {
-    switch (tag) {
-        case ANDROID_LENS_DISTORTION:
-            return "ANDROID_LENS_DISTORTION";
-        case ANDROID_LENS_INTRINSIC_CALIBRATION:
-            return "ANDROID_LENS_INTRINSIC_CALIBRATION";
-        case ANDROID_LENS_POSE_TRANSLATION:
-            return "ANDROID_LENS_POSE_TRANSLATION";
-        case ANDROID_LENS_POSE_ROTATION:
-            return "ANDROID_LENS_POSE_ROTATION";
-        default:
-            LOG(WARNING) << "Cannot recognize the tag: " << tag;
-            return {};
-    }
-}
-
-bool getParam(const camera_metadata_t* metadata,
-              uint32_t tag,
-              int size,
-              float* param) {
-    camera_metadata_ro_entry_t entry = camera_metadata_ro_entry_t();
-    int rc = find_camera_metadata_ro_entry(metadata, tag, &entry);
-
-    if (rc != 0) {
-        LOG(ERROR) << "No metadata found for " << tagToString(tag);
-        return false;
-    }
-
-    if (entry.count != size || entry.type != TYPE_FLOAT) {
-        LOG(ERROR) << "Unexpected size or type for " << tagToString(tag);
-        return false;
-    }
-
-    const float* lensParam = entry.data.f;
-    for (int i = 0; i < size; i++) {
-        param[i] = lensParam[i];
-    }
-    return true;
-}
-
-bool getAndroidCameraParams(sp<IEvsCamera> camera,
-                            const string& cameraId,
-                            AndroidCameraParams& params) {
-    if (camera == nullptr) {
-        LOG(WARNING) << __FUNCTION__ << "The EVS camera object is invalid";
-        return {};
-    }
-
-    CameraDesc desc = {};
-    camera->getPhysicalCameraInfo(cameraId, [&desc](const CameraDesc& info) {
-        desc = info;
-    });
-
-    if (desc.metadata.size() == 0) {
-        LOG(ERROR) << "No metadata found for " << desc.v1.cameraId;
-        return false;
-    }
-
-    const camera_metadata_t* metadata =
-        reinterpret_cast<camera_metadata_t*>(&desc.metadata[0]);
-
-    // Look for ANDROID_LENS_DISTORTION
-    if (!getParam(metadata,
-                  ANDROID_LENS_DISTORTION,
-                  kSizeLensDistortion,
-                  &params.lensDistortion[0])) {
-        return false;
-    }
-
-    // Look for ANDROID_LENS_INTRINSIC_CALIBRATION
-    if (!getParam(metadata,
-                  ANDROID_LENS_INTRINSIC_CALIBRATION,
-                  kSizeLensIntrinsicCalibration,
-                  &params.lensIntrinsicCalibration[0])) {
-        return false;
-    }
-
-    // Look for ANDROID_LENS_POSE_TRANSLATION
-    if (!getParam(metadata,
-                  ANDROID_LENS_POSE_TRANSLATION,
-                  kSizeLensPoseTranslation,
-                  &params.lensPoseTranslation[0])) {
-        return false;
-    }
-
-    // Look for ANDROID_LENS_POSE_ROTATION
-    if (!getParam(metadata,
-                  ANDROID_LENS_POSE_ROTATION,
-                  kSizeLensPoseRotation,
-                  &params.lensPoseRotation[0])) {
-        return false;
-    }
-
-    return true;
-}
-
-vector<SurroundViewCameraParams> convertToSurroundViewCameraParams(
-        const map<string, AndroidCameraParams>& androidCameraParamsMap) {
-    vector<SurroundViewCameraParams> result;
-
-    // TODO(b/156101189): the cameras are in random order now. They need to be
-    // sorted based on the camera position info from config file.
-    for (const auto& entry : androidCameraParamsMap) {
-        SurroundViewCameraParams svParams;
-
-        // Android Camera format for intrinsics: [f_x, f_y, c_x, c_y, s]
-        //
-        // To corelib:
-        // SurroundViewCameraParams.intrinsics =
-        //         [ f_x,   s, c_x,
-        //             0, f_y, c_y,
-        //             0,   0,   1 ];
-        const float* intrinsics = &entry.second.lensIntrinsicCalibration[0];
-        svParams.intrinsics[0] = intrinsics[0];
-        svParams.intrinsics[1] = intrinsics[4];
-        svParams.intrinsics[2] = intrinsics[2];
-        svParams.intrinsics[3] = 0;
-        svParams.intrinsics[4] = intrinsics[1];
-        svParams.intrinsics[5] = intrinsics[3];
-        svParams.intrinsics[6] = 0;
-        svParams.intrinsics[7] = 0;
-        svParams.intrinsics[8] = 1;
-
-        // Android Camera format for lens distortion:
-        //         Radial: [kappa_1, kappa_2, kappa_3]
-        //         Tangential: [kappa_4, kappa_5]
-        //
-        // To corelib:
-        // SurroundViewCameraParams.distortion =
-        //         [kappa_1, kappa_2, kappa_3, kappa_4];
-        const float* distortion = &entry.second.lensDistortion[0];
-        svParams.distorion[0] = distortion[0];
-        svParams.distorion[1] = distortion[1];
-        svParams.distorion[2] = distortion[2];
-        svParams.distorion[3] = distortion[3];
-
-        // Android Camera format for rotation:
-        //         quaternion coefficients (x,y,z,w)
-        //
-        // To corelib:
-        //         theta = 2 * acos(w)
-        //         a_x = x / sin(theta/2)
-        //         a_y = y / sin(theta/2)
-        //         a_z = z / sin(theta/2)
-        // SurroundViewCameraParams.rvec =
-        //         [theta * a_x, theta * a_y, theta * a_z];
-        const float* rotation = &entry.second.lensPoseRotation[0];
-        const float theta = 2 * acos(rotation[3]);
-        const float a_x = rotation[0] / sin(theta / 2);
-        const float a_y = rotation[1] / sin(theta / 2);
-        const float a_z = rotation[2] / sin(theta / 2);
-        svParams.rvec[0] = theta * a_x;
-        svParams.rvec[1] = theta * a_y;
-        svParams.rvec[2] = theta * a_z;
-
-        // Android Camera format for translation: Translation = (x,y,z)
-        //
-        // To corelib:
-        // SurroundViewCameraParams.tvec = [x, y, z];
-        const float* translation = &entry.second.lensPoseTranslation[0];
-        svParams.tvec[0] = translation[0];
-        svParams.tvec[1] = translation[1];
-        svParams.tvec[2] = translation[2];
-
-        LOG(INFO) << "Camera parameters for " << entry.first
-                  << " have been converted to SV core lib format successfully";
-        result.emplace_back(svParams);
-    }
-
-    return result;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
diff --git a/cpp/surround_view/service-impl/CameraUtils.h b/cpp/surround_view/service-impl/CameraUtils.h
deleted file mode 100644
index 1fbc8d4..0000000
--- a/cpp/surround_view/service-impl/CameraUtils.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <system/camera_metadata.h>
-
-#include <string>
-#include <vector>
-
-#include "core_lib.h"
-
-using ::android::hardware::automotive::evs::V1_1::IEvsCamera;
-using ::android_auto::surround_view::SurroundViewCameraParams;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-const int kSizeLensDistortion = 5;
-const int kSizeLensIntrinsicCalibration = 5;
-const int kSizeLensPoseTranslation = 3;
-const int kSizeLensPoseRotation = 4;
-
-// Camera parameters that the Android Camera team defines.
-struct AndroidCameraParams {
-    float lensDistortion[kSizeLensDistortion];
-    float lensIntrinsicCalibration[kSizeLensIntrinsicCalibration];
-    float lensPoseTranslation[kSizeLensPoseTranslation];
-    float lensPoseRotation[kSizeLensPoseRotation];
-};
-
-// Gets the underlying physical camera ids for logical camera.
-// If the given camera is not a logical, its own id will be returned.
-std::vector<std::string> getPhysicalCameraIds(android::sp<IEvsCamera> camera);
-
-// Gets the intrinsic/extrinsic parameters for the given physical camera id.
-// Returns true if the parameters are obtained successfully. Returns false
-// otherwise.
-bool getAndroidCameraParams(android::sp<IEvsCamera> camera,
-                            const std::string& cameraId,
-                            AndroidCameraParams& params);
-
-// Converts the camera parameters from Android Camera format into Surround View
-// core lib format.
-std::vector<SurroundViewCameraParams> convertToSurroundViewCameraParams(
-        const std::map<std::string, AndroidCameraParams>& androidCameraParamsMap);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/CarModelConfigReader.cpp b/cpp/surround_view/service-impl/CarModelConfigReader.cpp
deleted file mode 100644
index 7be6cb0..0000000
--- a/cpp/surround_view/service-impl/CarModelConfigReader.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "CarModelConfigReader.h"
-#include "ConfigReaderUtil.h"
-#include "MathHelp.h"
-#include "core_lib.h"
-
-#include <android-base/logging.h>
-#include <tinyxml2.h>
-#include <sstream>
-#include <string>
-#include <utility>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Macro returning IoStatus::ERROR_READ_ANIMATION if condition evaluates to false.
-#define RETURN_ERROR_STATUS_IF_FALSE(cond)         \
-    do {                                           \
-        if (!(cond)) {                             \
-            return IOStatus::ERROR_READ_ANIMATION; \
-        }                                          \
-    } while (0)
-
-using tinyxml2::XML_SUCCESS;
-using tinyxml2::XMLDocument;
-using tinyxml2::XMLElement;
-
-namespace {
-
-bool ReadValueHex(const XMLElement* parent, const char* elementName, uint32_t* hex) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    RETURN_IF_FALSE(ElementHasText(element));
-    *hex = std::stoul(element->GetText(), nullptr, 16);
-    return true;
-}
-
-bool ReadValueList(const XMLElement* parent, const char* elementName,
-                   std::vector<std::string>* valueList) {
-    valueList->clear();
-    for (const XMLElement* elem = parent->FirstChildElement(elementName); elem != nullptr;
-         elem = elem->NextSiblingElement(elementName)) {
-        RETURN_IF_FALSE(ElementHasText(elem));
-        valueList->push_back(std::string(elem->GetText()));
-    }
-    return true;
-}
-
-// ReadValue for SurroundView2dParams::BlendingType.
-bool ReadAnimationType(const XMLElement* parent, const char* elementName, AnimationType* type) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    RETURN_IF_FALSE(ElementHasText(element));
-    const std::string animationTypeStr(element->GetText());
-
-    if (animationTypeStr == "RotationAngle") {
-        *type = AnimationType::ROTATION_ANGLE;
-    } else if (animationTypeStr == "RotationSpeed") {
-        *type = AnimationType::ROTATION_SPEED;
-    } else if (animationTypeStr == "Translation") {
-        *type = AnimationType::TRANSLATION;
-    } else if (animationTypeStr == "SwitchTextureOnce") {
-        *type = AnimationType::SWITCH_TEXTURE_ONCE;
-    } else if (animationTypeStr == "AdjustGammaOnce") {
-        *type = AnimationType::ADJUST_GAMMA_ONCE;
-    } else if (animationTypeStr == "SwitchTextureRepeat") {
-        *type = AnimationType::SWITCH_TEXTURE_REPEAT;
-    } else if (animationTypeStr == "AdjustGammaRepeat") {
-        *type = AnimationType::ADJUST_GAMMA_REPEAT;
-    } else {
-        LOG(ERROR) << "Unknown AnimationType specified: " << animationTypeStr;
-        return false;
-    }
-    return true;
-}
-
-bool ReadRange(const XMLElement* parent, const char* elementName, Range* range) {
-    const XMLElement* rangeElem = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &rangeElem));
-    {
-        RETURN_IF_FALSE(ReadValue(rangeElem, "Start", &range->start));
-        RETURN_IF_FALSE(ReadValue(rangeElem, "End", &range->end));
-    }
-    return true;
-}
-
-bool ReadFloat3(const XMLElement* parent, const char* elementName, std::array<float, 3>* float3) {
-    const XMLElement* arrayElem = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &arrayElem));
-    {
-        RETURN_IF_FALSE(ReadValue(arrayElem, "X", &float3->at(0)));
-        RETURN_IF_FALSE(ReadValue(arrayElem, "Y", &float3->at(1)));
-        RETURN_IF_FALSE(ReadValue(arrayElem, "Z", &float3->at(2)));
-    }
-    return true;
-}
-
-// Generic template for reading a animation op, each op type must be specialized.
-template <typename OpType>
-bool ReadOp(const XMLElement* opElem, OpType* op) {
-    (void)opElem;
-    (void)op;
-    LOG(ERROR) << "Unexpected internal error: Op type in not supported.";
-    return false;
-}
-
-// Reads vhal property.
-bool ReadVhalProperty(const XMLElement* parent, const char* elementName, uint64_t* vhalProperty) {
-    const XMLElement* vhalPropElem = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &vhalPropElem));
-    {
-        uint32_t propertyId;
-        uint32_t areaId;
-        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "PropertyId", &propertyId));
-        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "AreaId", &areaId));
-        *vhalProperty = (static_cast<uint64_t>(propertyId) << 32) | areaId;
-    }
-    return true;
-}
-
-template <>
-bool ReadOp<RotationOp>(const XMLElement* rotationOpElem, RotationOp* rotationOp) {
-    RETURN_IF_FALSE(ReadVhalProperty(rotationOpElem, "VhalProperty", &rotationOp->vhalProperty));
-
-    RETURN_IF_FALSE(ReadAnimationType(rotationOpElem, "AnimationType", &rotationOp->type));
-
-    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationAxis", &rotationOp->axis.axisVector));
-
-    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationPoint", &rotationOp->axis.rotationPoint));
-
-    RETURN_IF_FALSE(
-            ReadValue(rotationOpElem, "DefaultRotationValue", &rotationOp->defaultRotationValue));
-
-    RETURN_IF_FALSE(ReadValue(rotationOpElem, "AnimationTimeMs", &rotationOp->animationTime));
-
-    RETURN_IF_FALSE(ReadRange(rotationOpElem, "RotationRange", &rotationOp->rotationRange));
-
-    RETURN_IF_FALSE(ReadRange(rotationOpElem, "VhalRange", &rotationOp->vhalRange));
-
-    return true;
-}
-
-template <>
-bool ReadOp<TranslationOp>(const XMLElement* translationOpElem, TranslationOp* translationOp) {
-    RETURN_IF_FALSE(
-            ReadVhalProperty(translationOpElem, "VhalProperty", &translationOp->vhalProperty));
-
-    RETURN_IF_FALSE(ReadAnimationType(translationOpElem, "AnimationType", &translationOp->type));
-
-    RETURN_IF_FALSE(ReadFloat3(translationOpElem, "Direction", &translationOp->direction));
-
-    RETURN_IF_FALSE(ReadValue(translationOpElem, "DefaultTranslationValue",
-                              &translationOp->defaultTranslationValue));
-
-    RETURN_IF_FALSE(ReadValue(translationOpElem, "AnimationTimeMs", &translationOp->animationTime));
-
-    RETURN_IF_FALSE(
-            ReadRange(translationOpElem, "TranslationRange", &translationOp->translationRange));
-
-    RETURN_IF_FALSE(ReadRange(translationOpElem, "VhalRange", &translationOp->vhalRange));
-
-    return true;
-}
-
-template <>
-bool ReadOp<TextureOp>(const XMLElement* textureOpElem, TextureOp* textureOp) {
-    RETURN_IF_FALSE(ReadVhalProperty(textureOpElem, "VhalProperty", &textureOp->vhalProperty));
-
-    RETURN_IF_FALSE(ReadAnimationType(textureOpElem, "AnimationType", &textureOp->type));
-
-    RETURN_IF_FALSE(ReadValue(textureOpElem, "DefaultTexture", &textureOp->defaultTexture));
-
-    RETURN_IF_FALSE(ReadValue(textureOpElem, "AnimationTimeMs", &textureOp->animationTime));
-
-    RETURN_IF_FALSE(ReadRange(textureOpElem, "TextureRange", &textureOp->textureRange));
-
-    RETURN_IF_FALSE(ReadRange(textureOpElem, "VhalRange", &textureOp->vhalRange));
-
-    return true;
-}
-
-template <>
-bool ReadOp<GammaOp>(const XMLElement* gammaOpElem, GammaOp* gammaOp) {
-    RETURN_IF_FALSE(ReadVhalProperty(gammaOpElem, "VhalProperty", &gammaOp->vhalProperty));
-
-    RETURN_IF_FALSE(ReadAnimationType(gammaOpElem, "AnimationType", &gammaOp->type));
-
-    RETURN_IF_FALSE(ReadValue(gammaOpElem, "AnimationTimeMs", &gammaOp->animationTime));
-
-    RETURN_IF_FALSE(ReadRange(gammaOpElem, "GammaRange", &gammaOp->gammaRange));
-
-    RETURN_IF_FALSE(ReadRange(gammaOpElem, "VhalRange", &gammaOp->vhalRange));
-
-    return true;
-}
-
-template <typename OpType>
-bool ReadAllOps(const XMLElement* animationElem, const char* elemName,
-                std::map<uint64_t, std::vector<OpType>>* mapOps) {
-    for (const XMLElement* elem = animationElem->FirstChildElement(elemName); elem != nullptr;
-         elem = elem->NextSiblingElement(elemName)) {
-        OpType op;
-        RETURN_IF_FALSE(ReadOp(elem, &op));
-        if (mapOps->find(op.vhalProperty) == mapOps->end()) {
-            mapOps->emplace(op.vhalProperty, std::vector<OpType>());
-        }
-        mapOps->at(op.vhalProperty).push_back(op);
-    }
-    return true;
-}
-
-bool ReadAnimation(const XMLElement* animationElem, AnimationInfo* animationInfo) {
-    RETURN_IF_FALSE(ReadValue(animationElem, "PartId", &animationInfo->partId));
-    RETURN_IF_FALSE(ReadValue(animationElem, "ParentPartId", &animationInfo->parentId));
-
-    // Child Part Ids (Optional)
-    const XMLElement* childPartsElem = nullptr;
-    GetElement(animationElem, "ChildParts", &childPartsElem);
-    if (childPartsElem != nullptr) {
-        RETURN_IF_FALSE(ReadValueList(childPartsElem, "PartId", &animationInfo->childIds));
-    }
-
-    // Set to the default Identity.
-    animationInfo->pose = gMat4Identity;
-
-    // All animation operations.
-    RETURN_IF_FALSE(ReadAllOps(animationElem, "RotationOp", &animationInfo->rotationOpsMap));
-    RETURN_IF_FALSE(ReadAllOps(animationElem, "TranslationOp", &animationInfo->translationOpsMap));
-    RETURN_IF_FALSE(ReadAllOps(animationElem, "TextureOp", &animationInfo->textureOpsMap));
-    RETURN_IF_FALSE(ReadAllOps(animationElem, "GammaOp", &animationInfo->gammaOpsMap));
-    return true;
-}
-
-bool ReadAllAnimations(const XMLElement* rootElem, std::vector<AnimationInfo>* animations) {
-    animations->clear();
-    // Loop over animation elements.
-    for (const XMLElement* elem = rootElem->FirstChildElement("Animation"); elem != nullptr;
-         elem = elem->NextSiblingElement("Animation")) {
-        AnimationInfo animationInfo;
-        RETURN_IF_FALSE(ReadAnimation(elem, &animationInfo));
-        animations->push_back(animationInfo);
-    }
-    return true;
-}
-
-}  // namespace
-
-IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
-                            AnimationConfig* animationConfig) {
-    XMLDocument xmlDoc;
-
-    /* load and parse a configuration file */
-    xmlDoc.LoadFile(carModelConfigFile.c_str());
-    if (xmlDoc.ErrorID() != XML_SUCCESS) {
-        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
-        return IOStatus::ERROR_READ_ANIMATION;
-    }
-
-    const XMLElement* rootElem = xmlDoc.RootElement();
-    if (strcmp(rootElem->Name(), "SurroundViewCarModelConfig")) {
-        LOG(ERROR) << "Config file is not in the required format: " << carModelConfigFile;
-        return IOStatus::ERROR_READ_ANIMATION;
-    }
-
-    // version
-    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &animationConfig->version));
-
-    // animations
-    RETURN_ERROR_STATUS_IF_FALSE(ReadAllAnimations(rootElem, &animationConfig->animations));
-
-    return IOStatus::OK;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/CarModelConfigReader.h b/cpp/surround_view/service-impl/CarModelConfigReader.h
deleted file mode 100644
index c2e9049..0000000
--- a/cpp/surround_view/service-impl/CarModelConfigReader.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
-#define SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
-
-#include <string>
-
-#include "IOModuleCommon.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
-                            AnimationConfig* animationConfig);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
diff --git a/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp b/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp
deleted file mode 100644
index 81f8192..0000000
--- a/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "IoModuleTests"
-
-#include "CarModelConfigReader.h"
-
-#include "MathHelp.h"
-#include "core_lib.h"
-
-#include <gtest/gtest.h>
-#include <string>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-TEST(CarModelConfigReaderTests, CarModelReadConfigSuccess) {
-    AnimationConfig animationConfig;
-    EXPECT_EQ(ReadCarModelConfig("/vendor/etc/automotive/sv/sv_sample_car_model_config.xml",
-                                 &animationConfig),
-              IOStatus::OK);
-
-    EXPECT_EQ(animationConfig.version, "1.0");
-
-    ASSERT_EQ(animationConfig.animations.size(), 2);
-
-    {
-        AnimationInfo doorAnimation = animationConfig.animations.at(0);
-        EXPECT_EQ(doorAnimation.partId, "door");
-        EXPECT_EQ(doorAnimation.childIds.size(), 1);
-        EXPECT_EQ(doorAnimation.pose, gMat4Identity);
-
-        EXPECT_EQ(doorAnimation.rotationOpsMap.size(), 1);
-        {
-            RotationOp rotationOp = (doorAnimation.rotationOpsMap.at(0x16000B0000000001)).at(0);
-            EXPECT_EQ(rotationOp.vhalProperty, 0x16000B0000000001);
-            EXPECT_EQ(rotationOp.type, AnimationType::ROTATION_ANGLE);
-            EXPECT_EQ(rotationOp.animationTime, 2000);
-            std::array<float, 3> axis = {0, 0, 1};
-            EXPECT_EQ(rotationOp.axis.axisVector, axis);
-            std::array<float, 3> point = {0, 0, 0};
-            EXPECT_EQ(rotationOp.axis.rotationPoint, point);
-            EXPECT_EQ(rotationOp.rotationRange.start, 0.0);
-            EXPECT_EQ(rotationOp.rotationRange.end, 90.0);
-            EXPECT_EQ(rotationOp.vhalRange.start, 0);
-            EXPECT_EQ(rotationOp.vhalRange.end, 0x7FFFFFFF);
-        }
-    }
-
-    {
-        AnimationInfo windowAnimation = animationConfig.animations.at(1);
-        EXPECT_EQ(windowAnimation.partId, "window");
-        EXPECT_EQ(windowAnimation.childIds.size(), 0);
-        EXPECT_EQ(windowAnimation.pose, gMat4Identity);
-
-        EXPECT_EQ(windowAnimation.translationOpsMap.size(), 1);
-        {
-            TranslationOp translationOp =
-                    (windowAnimation.translationOpsMap.at(0x13000BC000000010)).at(0);
-            EXPECT_EQ(translationOp.vhalProperty, 0x13000BC000000010);
-            EXPECT_EQ(translationOp.type, AnimationType::TRANSLATION);
-            EXPECT_EQ(translationOp.animationTime, 2000);
-            std::array<float, 3> dir = {0.0, 0.0, -1.0};
-            EXPECT_EQ(translationOp.direction, dir);
-            EXPECT_EQ(translationOp.defaultTranslationValue, 0.0);
-            EXPECT_EQ(translationOp.translationRange.start, 0.0);
-            EXPECT_EQ(translationOp.translationRange.end, 1.0);
-            EXPECT_EQ(translationOp.vhalRange.start, 0);
-            EXPECT_EQ(translationOp.vhalRange.end, 0x7FFFFFFF);
-        }
-    }
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/ConfigReader.cpp b/cpp/surround_view/service-impl/ConfigReader.cpp
deleted file mode 100644
index cc1c81b..0000000
--- a/cpp/surround_view/service-impl/ConfigReader.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "ConfigReader.h"
-#include "ConfigReaderUtil.h"
-#include "core_lib.h"
-
-#include <android-base/logging.h>
-#include <tinyxml2.h>
-#include <sstream>
-#include <string>
-#include <utility>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using tinyxml2::XML_SUCCESS;
-using tinyxml2::XMLDocument;
-using tinyxml2::XMLElement;
-
-using android_auto::surround_view::SurroundView2dParams;
-using android_auto::surround_view::SurroundView3dParams;
-
-namespace {
-
-// Macro returning IoStatus::ERROR_CONFIG_FILE_FORMAT if condition evaluates to false.
-#define RETURN_ERROR_STATUS_IF_FALSE(cond)             \
-    do {                                               \
-        if (!(cond)) {                                 \
-            return IOStatus::ERROR_CONFIG_FILE_FORMAT; \
-        }                                              \
-    } while (0)
-
-// ReadValue for SurroundView2dParams::BlendingType.
-bool ReadValue2dBlendType(const XMLElement* parent, const char* elementName,
-                          SurroundView2dParams::BlendingType* value) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    RETURN_IF_FALSE(ElementHasText(element));
-    const std::string blendingTypeStr(element->GetText());
-
-    if (blendingTypeStr == "multiband") {
-        *value = SurroundView2dParams::BlendingType::MULTIBAND;
-    } else if (blendingTypeStr == "alpha") {
-        *value = SurroundView2dParams::BlendingType::ALPHA;
-    } else {
-        LOG(ERROR) << "Unknown BlendingType specified: " << blendingTypeStr;
-        return false;
-    }
-    return true;
-}
-
-bool ReadSvConfig2d(const XMLElement* parent, SvConfig2d* sv2dConfig) {
-    RETURN_IF_FALSE(ReadValue(parent, "Sv2dEnabled", &sv2dConfig->sv2dEnabled));
-    if (!sv2dConfig->sv2dEnabled) {
-        return true;
-    }
-
-    SurroundView2dParams* sv2dParams = &sv2dConfig->sv2dParams;
-    const XMLElement* param2dElem = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, "Sv2dParams", &param2dElem));
-    {
-        // OutputResolution
-        const XMLElement* outputResolutionElem = nullptr;
-        RETURN_IF_FALSE(GetElement(param2dElem, "OutputResolution", &outputResolutionElem));
-        {
-            RETURN_IF_FALSE(
-                    ReadValue(outputResolutionElem, "Width", &sv2dParams->resolution.width));
-            RETURN_IF_FALSE(
-                    ReadValue(outputResolutionElem, "Height", &sv2dParams->resolution.height));
-        }
-
-        // GroundMapping
-        const XMLElement* groundMappingElem = nullptr;
-        RETURN_IF_FALSE(GetElement(param2dElem, "GroundMapping", &groundMappingElem));
-        {
-            RETURN_IF_FALSE(
-                    ReadValue(groundMappingElem, "Width", &sv2dParams->physical_size.width));
-            RETURN_IF_FALSE(
-                    ReadValue(groundMappingElem, "Height", &sv2dParams->physical_size.height));
-
-            // Center
-            const XMLElement* centerElem = nullptr;
-            RETURN_IF_FALSE(GetElement(groundMappingElem, "Center", &centerElem));
-            {
-                RETURN_IF_FALSE(ReadValue(centerElem, "X", &sv2dParams->physical_center.x));
-                RETURN_IF_FALSE(ReadValue(centerElem, "Y", &sv2dParams->physical_center.y));
-            }
-        }
-
-        // Car Bounding Box
-        const XMLElement* carBoundingBoxElem = nullptr;
-        RETURN_IF_FALSE(GetElement(param2dElem, "CarBoundingBox", &carBoundingBoxElem));
-        {
-            RETURN_IF_FALSE(
-                    ReadValue(carBoundingBoxElem, "Width", &sv2dConfig->carBoundingBox.width));
-            RETURN_IF_FALSE(
-                    ReadValue(carBoundingBoxElem, "Height", &sv2dConfig->carBoundingBox.height));
-
-            // Center
-            const XMLElement* leftTopCornerElem = nullptr;
-            RETURN_IF_FALSE(GetElement(carBoundingBoxElem, "LeftTopCorner", &leftTopCornerElem));
-            {
-                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "X", &sv2dConfig->carBoundingBox.x));
-                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "Y", &sv2dConfig->carBoundingBox.y));
-            }
-        }
-
-        // Blending type
-        const XMLElement* blendingTypeElem = nullptr;
-        RETURN_IF_FALSE(GetElement(param2dElem, "BlendingType", &blendingTypeElem));
-        {
-            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "HighQuality",
-                                                 &sv2dParams->high_quality_blending));
-            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "LowQuality",
-                                                 &sv2dParams->low_quality_blending));
-        }
-
-        // GPU Acceleration enabled or not
-        RETURN_IF_FALSE(ReadValue(param2dElem, "GpuAccelerationEnabled",
-                                  &sv2dParams->gpu_acceleration_enabled));
-    }
-    return true;
-}
-
-bool ReadSvConfig3d(const XMLElement* parent, SvConfig3d* sv3dConfig) {
-    RETURN_IF_FALSE(ReadValue(parent, "Sv3dEnabled", &sv3dConfig->sv3dEnabled));
-    if (!sv3dConfig->sv3dEnabled) {
-        return true;
-    }
-    RETURN_IF_FALSE(ReadValue(parent, "Sv3dAnimationsEnabled", &sv3dConfig->sv3dAnimationsEnabled));
-
-    if (sv3dConfig->sv3dAnimationsEnabled) {
-        RETURN_IF_FALSE(ReadValue(parent, "CarModelConfigFile", &sv3dConfig->carModelConfigFile));
-    }
-
-    RETURN_IF_FALSE(ReadValue(parent, "CarModelObjFile", &sv3dConfig->carModelObjFile));
-
-    SurroundView3dParams* sv3dParams = &sv3dConfig->sv3dParams;
-    const XMLElement* param3dElem = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, "Sv3dParams", &param3dElem));
-    {
-        // OutputResolution
-        const XMLElement* outputResolutionElem = nullptr;
-        RETURN_IF_FALSE(GetElement(param3dElem, "OutputResolution", &outputResolutionElem));
-        {
-            RETURN_IF_FALSE(
-                    ReadValue(outputResolutionElem, "Width", &sv3dParams->resolution.width));
-            RETURN_IF_FALSE(
-                    ReadValue(outputResolutionElem, "Height", &sv3dParams->resolution.height));
-        }
-
-        // Bowl Params
-        const XMLElement* bowlParamsElem = nullptr;
-        RETURN_IF_FALSE(GetElement(param3dElem, "BowlParams", &bowlParamsElem));
-        {
-            RETURN_IF_FALSE(ReadValue(bowlParamsElem, "PlaneRadius", &sv3dParams->plane_radius));
-            RETURN_IF_FALSE(
-                    ReadValue(bowlParamsElem, "PlaneDivisions", &sv3dParams->plane_divisions));
-            RETURN_IF_FALSE(ReadValue(bowlParamsElem, "CurveHeight", &sv3dParams->curve_height));
-            RETURN_IF_FALSE(
-                    ReadValue(bowlParamsElem, "CurveDivisions", &sv3dParams->curve_divisions));
-            RETURN_IF_FALSE(
-                    ReadValue(bowlParamsElem, "AngularDivisions", &sv3dParams->angular_divisions));
-            RETURN_IF_FALSE(
-                    ReadValue(bowlParamsElem, "CurveCoefficient", &sv3dParams->curve_coefficient));
-        }
-
-        // High Quality details
-        const XMLElement* highQualityDetailsElem = nullptr;
-        GetElement(param3dElem, "HighQualityDetails", &highQualityDetailsElem);
-        {
-            RETURN_IF_FALSE(ReadValue(highQualityDetailsElem, "Shadows",
-                                      &sv3dParams->high_details_shadows));
-            RETURN_IF_FALSE(ReadValue(highQualityDetailsElem, "Reflections",
-                                      &sv3dParams->high_details_reflections));
-        }
-    }
-    return true;
-}
-
-bool ReadCameraConfig(const XMLElement* parent, CameraConfig* cameraConfig) {
-    const XMLElement* cameraConfigElem = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, "CameraConfig", &cameraConfigElem));
-    {
-        // Evs Group Id
-        RETURN_IF_FALSE(ReadValue(cameraConfigElem, "EvsGroupId", &cameraConfig->evsGroupId));
-
-        // Evs Cameras Ids
-        const XMLElement* cameraIdsElem = nullptr;
-        RETURN_IF_FALSE(GetElement(cameraConfigElem, "EvsCameraIds", &cameraIdsElem));
-        {
-            cameraConfig->evsCameraIds.resize(4);
-            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Front", &cameraConfig->evsCameraIds[0]));
-            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Right", &cameraConfig->evsCameraIds[1]));
-            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Rear", &cameraConfig->evsCameraIds[2]));
-            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Left", &cameraConfig->evsCameraIds[3]));
-        }
-
-        // Masks (Optional).
-        const XMLElement* masksElem = nullptr;
-        GetElement(cameraConfigElem, "Masks", &masksElem);
-        if (masksElem != nullptr) {
-            cameraConfig->maskFilenames.resize(4);
-            RETURN_IF_FALSE(ReadValue(masksElem, "Front", &cameraConfig->maskFilenames[0]));
-            RETURN_IF_FALSE(ReadValue(masksElem, "Right", &cameraConfig->maskFilenames[1]));
-            RETURN_IF_FALSE(ReadValue(masksElem, "Rear", &cameraConfig->maskFilenames[2]));
-            RETURN_IF_FALSE(ReadValue(masksElem, "Left", &cameraConfig->maskFilenames[3]));
-        }
-    }
-    return true;
-}
-
-}  // namespace
-
-IOStatus ReadSurroundViewConfig(const std::string& configFile, SurroundViewConfig* svConfig) {
-    XMLDocument xmlDoc;
-
-    // load and parse a configuration file
-    xmlDoc.LoadFile(configFile.c_str());
-    if (xmlDoc.ErrorID() != XML_SUCCESS) {
-        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
-        return IOStatus::ERROR_READ_CONFIG_FILE;
-    }
-
-    const XMLElement* rootElem = xmlDoc.RootElement();
-    if (strcmp(rootElem->Name(), "SurroundViewConfig")) {
-        LOG(ERROR) << "Config file is not in the required format: " << configFile;
-        return IOStatus::ERROR_READ_CONFIG_FILE;
-    }
-
-    // version
-    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &svConfig->version));
-
-    // CameraConfig
-    RETURN_ERROR_STATUS_IF_FALSE(ReadCameraConfig(rootElem, &svConfig->cameraConfig));
-
-    // Surround View 2D
-    RETURN_ERROR_STATUS_IF_FALSE(ReadSvConfig2d(rootElem, &svConfig->sv2dConfig));
-
-    // Surround View 3D
-    RETURN_ERROR_STATUS_IF_FALSE(ReadSvConfig3d(rootElem, &svConfig->sv3dConfig));
-
-    return IOStatus::OK;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/ConfigReader.h b/cpp/surround_view/service-impl/ConfigReader.h
deleted file mode 100644
index 7bdbe2a..0000000
--- a/cpp/surround_view/service-impl/ConfigReader.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
-#define SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
-
-#include <string>
-
-#include "IOModuleCommon.h"
-#include "core_lib.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Parses the surround view config xml into struct SurroundViewConfig.
-IOStatus ReadSurroundViewConfig(const std::string& configFile, SurroundViewConfig* svConfig);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
diff --git a/cpp/surround_view/service-impl/ConfigReaderTests.cpp b/cpp/surround_view/service-impl/ConfigReaderTests.cpp
deleted file mode 100644
index 7d12322..0000000
--- a/cpp/surround_view/service-impl/ConfigReaderTests.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "ConfigReaderTests"
-
-#include "ConfigReader.h"
-
-#include "core_lib.h"
-
-#include <gtest/gtest.h>
-#include <string>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-using android_auto::surround_view::SurroundView2dParams;
-using android_auto::surround_view::SurroundView3dParams;
-
-TEST(ConfigReaderTests, ReadConfigSuccess) {
-    SurroundViewConfig svConfig;
-    EXPECT_EQ(ReadSurroundViewConfig("/vendor/etc/automotive/sv/sv_sample_config.xml", &svConfig),
-              IOStatus::OK);
-
-    EXPECT_EQ(svConfig.version, "1.0");
-
-    // Camera config
-    EXPECT_EQ(svConfig.cameraConfig.evsGroupId, "v4l2loopback_group0");
-
-    // Camera Ids
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[0], "/dev/video60");
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[1], "/dev/video61");
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[2], "/dev/video62");
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[3], "/dev/video63");
-
-    // Masks
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames.size(), 4);
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[0], "/vendor/etc/automotive/sv/mask_front.png");
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[1], "/vendor/etc/automotive/sv/mask_right.png");
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[2], "/vendor/etc/automotive/sv/mask_rear.png");
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[3], "/vendor/etc/automotive/sv/mask_left.png");
-
-    // Surround view 2D
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dEnabled, true);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.width, 768);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.height, 1024);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.width, 9.0);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.height, 12.0);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.x, 0.0);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.y, 0.0);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.gpu_acceleration_enabled, false);
-    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.width, 2.0);
-    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.height, 3.0);
-    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.x, 1.0);
-    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.y, 1.5);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.high_quality_blending,
-              SurroundView2dParams::BlendingType::MULTIBAND);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.low_quality_blending,
-              SurroundView2dParams::BlendingType::ALPHA);
-
-    // Surround view 3D
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dEnabled, true);
-    EXPECT_NE(svConfig.sv3dConfig.carModelConfigFile, "");
-    EXPECT_NE(svConfig.sv3dConfig.carModelObjFile, "");
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_radius, 8.0);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_divisions, 50);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_height, 6.0);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_divisions, 50);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.angular_divisions, 90);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_coefficient, 3.0);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_shadows, true);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_reflections, true);
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/ConfigReaderUtil.cpp b/cpp/surround_view/service-impl/ConfigReaderUtil.cpp
deleted file mode 100644
index e5fe7c4..0000000
--- a/cpp/surround_view/service-impl/ConfigReaderUtil.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "ConfigReaderUtil.h"
-
-#include <android-base/logging.h>
-#include <tinyxml2.h>
-#include <utility>
-
-#include "core_lib.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using tinyxml2::XML_SUCCESS;
-using tinyxml2::XMLElement;
-
-bool ElementHasText(const XMLElement* element) {
-    if (element->GetText() == "") {
-        LOG(ERROR) << "Expected element to have text: " << element->Name();
-        return false;
-    }
-    return true;
-}
-
-bool GetElement(const XMLElement* parent, const char* elementName, XMLElement const** element) {
-    *element = parent->FirstChildElement(elementName);
-    if (*element == nullptr) {
-        LOG(ERROR) << "Expected element '" << elementName << "' in parent '" << parent->Name()
-                   << "' not found";
-        return false;
-    }
-    return true;
-}
-
-bool ReadValue(const XMLElement* parent, const char* elementName, bool* value) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    if (element->QueryBoolText(value) != XML_SUCCESS) {
-        LOG(ERROR) << "Failed to read valid boolean value from: " << element->Name();
-        return false;
-    }
-    return true;
-}
-
-bool ReadValue(const XMLElement* parent, const char* elementName, std::string* value) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    RETURN_IF_FALSE(ElementHasText(element));
-    *value = std::string(element->GetText());
-    return true;
-}
-
-bool ReadValue(const XMLElement* parent, const char* elementName, float* value) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    if (element->QueryFloatText(value) != XML_SUCCESS) {
-        LOG(ERROR) << "Failed to read valid float value from: " << element->Name();
-        return false;
-    }
-    return true;
-}
-
-bool ReadValue(const XMLElement* parent, const char* elementName, int* value) {
-    const XMLElement* element = nullptr;
-    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
-    if (element->QueryIntText(value) != XML_SUCCESS) {
-        LOG(ERROR) << "Failed to read valid int value from: " << element->Name();
-        return false;
-    }
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/ConfigReaderUtil.h b/cpp/surround_view/service-impl/ConfigReaderUtil.h
deleted file mode 100644
index 030cc0f..0000000
--- a/cpp/surround_view/service-impl/ConfigReaderUtil.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
-#define SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
-
-#include <tinyxml2.h>
-#include <sstream>
-#include <string>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Macro returning false if condition evaluates to false.
-#define RETURN_IF_FALSE(cond) \
-    do {                      \
-        if (!(cond)) {        \
-            return false;     \
-        }                     \
-    } while (0)
-
-// Returns true if element has text.
-bool ElementHasText(const tinyxml2::XMLElement* element);
-
-// Gets a xml element from the parent element, returns false if not found.
-bool GetElement(const tinyxml2::XMLElement* parent, const char* elementName,
-                tinyxml2::XMLElement const** element);
-
-// Reads a boolean value from a element, returns false if not found.
-bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, bool* value);
-
-// Reads a string value from a element, returns false if not found.
-bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, std::string* value);
-
-// Reads a float value from a element, returns false if not found.
-bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, float* value);
-
-// Reads a int value from a element, returns false if not found.
-bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, int* value);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
diff --git a/cpp/surround_view/service-impl/IOModule.cpp b/cpp/surround_view/service-impl/IOModule.cpp
deleted file mode 100644
index e1af11a..0000000
--- a/cpp/surround_view/service-impl/IOModule.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include <android-base/logging.h>
-
-#include "CarModelConfigReader.h"
-#include "ConfigReader.h"
-#include "IOModule.h"
-#include "ObjReader.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-IOModule::IOModule(const std::string& svConfigFile) :
-      mSvConfigFile(svConfigFile), mIsInitialized(false) {}
-
-IOStatus IOModule::initialize() {
-    if (mIsInitialized) {
-        LOG(INFO) << "IOModule is already initialized.";
-        return IOStatus::OK;
-    }
-
-    SurroundViewConfig svConfig;
-    IOStatus status;
-    if ((status = ReadSurroundViewConfig(mSvConfigFile, &svConfig)) != IOStatus::OK) {
-        LOG(ERROR) << "ReadSurroundViewConfig() failed.";
-        return status;
-    }
-
-    mIOModuleConfig.cameraConfig = svConfig.cameraConfig;
-    mIOModuleConfig.sv2dConfig = svConfig.sv2dConfig;
-    mIOModuleConfig.sv3dConfig = svConfig.sv3dConfig;
-
-    if (mIOModuleConfig.sv3dConfig.sv3dEnabled) {
-        // Read obj and mtl files.
-        if (!ReadObjFromFile(svConfig.sv3dConfig.carModelObjFile,
-                             &mIOModuleConfig.carModelConfig.carModel.partsMap)) {
-            LOG(ERROR) << "ReadObjFromFile() failed.";
-            return IOStatus::ERROR_READ_CAR_MODEL;
-        }
-        // Read animations.
-        if (mIOModuleConfig.sv3dConfig.sv3dAnimationsEnabled) {
-            if ((status = ReadCarModelConfig(svConfig.sv3dConfig.carModelConfigFile,
-                                             &mIOModuleConfig.carModelConfig.animationConfig)) !=
-                IOStatus::OK) {
-                LOG(ERROR) << "ReadObjFromFile() failed.";
-                return status;
-            }
-        }
-    }
-    mIsInitialized = true;
-    return IOStatus::OK;
-}
-
-bool IOModule::getConfig(IOModuleConfig* ioModuleConfig) {
-    if (!mIsInitialized) {
-        LOG(ERROR) << "IOModule not initalized.";
-        return false;
-    }
-    *ioModuleConfig = mIOModuleConfig;
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/IOModule.h b/cpp/surround_view/service-impl/IOModule.h
deleted file mode 100644
index 2e19dc5..0000000
--- a/cpp/surround_view/service-impl/IOModule.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-#ifndef SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
-#define SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
-
-#include "IOModuleCommon.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// I/O Module class processing all I/O related operations.
-class IOModule {
-public:
-    // Constructor with file name( and path) of config file.
-    IOModule(const std::string& svConfigFile);
-
-    // Reads all config files and stores parsed results in mIOModuleConfig.
-    IOStatus initialize();
-
-    // Gets config data read from files. initialize must be called this.
-    bool getConfig(IOModuleConfig* ioModuleConfig);
-
-private:
-    // Config string filename.
-    std::string mSvConfigFile;
-
-    // Indicates initialize success/fail.
-    bool mIsInitialized;
-
-    // Stores the parsed config.
-    IOModuleConfig mIOModuleConfig;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-#endif  // SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
diff --git a/cpp/surround_view/service-impl/IOModuleCommon.h b/cpp/surround_view/service-impl/IOModuleCommon.h
deleted file mode 100644
index 5550fd5..0000000
--- a/cpp/surround_view/service-impl/IOModuleCommon.h
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
-#define SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
-
-#include <string>
-
-#include "core_lib.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Struct for camera related configurations.
-// Note: Does not include camera intrinsics and extrinsics, these are specified in EVS metadata.
-struct CameraConfig {
-    // Id of logical group containing surronnd view cameras.
-    std::string evsGroupId;
-
-    // List of evs camera Ids  in order: front, right, rear, left.
-    std::vector<std::string> evsCameraIds;
-
-    // In order: front, right, rear, left.
-    std::vector<std::string> maskFilenames;
-};
-
-struct SvConfig2d {
-    // Bool flag for surround view 2d.
-    bool sv2dEnabled;
-
-    // Surround view 2d params.
-    android_auto::surround_view::SurroundView2dParams sv2dParams;
-
-    // Car model bounding box for 2d surround view.
-    // To be moved into sv 2d params.
-    android_auto::surround_view::BoundingBox carBoundingBox;
-};
-
-struct SvConfig3d {
-    // Bool flag for enabling/disabling surround view 3d.
-    bool sv3dEnabled;
-
-    // Bool flag for enabling/disabling animations.
-    bool sv3dAnimationsEnabled;
-
-    // Car model config file.
-    std::string carModelConfigFile;
-
-    // Car model obj file.
-    std::string carModelObjFile;
-
-    // Surround view 3d params.
-    android_auto::surround_view::SurroundView3dParams sv3dParams;
-};
-
-// Main struct in which surround view config is parsed into.
-struct SurroundViewConfig {
-    // Version info.
-    std::string version;
-
-    // Camera config.
-    CameraConfig cameraConfig;
-
-    // Surround view 2d config.
-    SvConfig2d sv2dConfig;
-
-    // Surround view 3d config.
-    SvConfig3d sv3dConfig;
-};
-
-struct Range {
-    // Range start.
-    // Start value may be greater than end value.
-    float start;
-
-    // Range end.
-    float end;
-};
-
-// Rotation axis
-struct RotationAxis {
-    // Unit axis direction vector.
-    std::array<float, 3> axisVector;
-
-    // Rotate about this point.
-    std::array<float, 3> rotationPoint;
-};
-
-enum AnimationType {
-    // Rotate a part about an axis from a start to end angle.
-    ROTATION_ANGLE = 0,
-
-    // Continuously rotate a part about an axis by a specified angular speed.
-    ROTATION_SPEED = 1,
-
-    // Linearly translates a part from one point to another.
-    TRANSLATION = 2,
-
-    // Switch to another texture once.
-    SWITCH_TEXTURE_ONCE = 3,
-
-    // Adjust the brightness of the texture once.
-    ADJUST_GAMMA_ONCE = 4,
-
-    // Repeatedly toggle between two textures.
-    SWITCH_TEXTURE_REPEAT = 5,
-
-    // Repeatedly toggle between two gamma values.
-    ADJUST_GAMMA_REPEAT = 6,
-};
-
-// Rotation operation
-struct RotationOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Rotation operation type.
-    AnimationType type;
-
-    // Rotation axis.
-    RotationAxis axis;
-
-    // Default rotation (angle/speed) value.
-    // It is used for default rotation when the signal is on while vhal_range is
-    // not provided.
-    float defaultRotationValue;
-
-    // Default animation time elapsed to finish the rotation operation.
-    // It is ignored if VHAL provides continuous signal value.
-    float animationTime;
-
-    // physical rotation range with start mapped to vhal_range start and
-    // end mapped to vhal_range end.
-    Range rotationRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-};
-
-// Translation operation.
-struct TranslationOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Translation operation type.
-    AnimationType type;
-
-    // Unit direction vector.
-    std::array<float, 3> direction;
-
-    // Default translation value.
-    // It is used for default translation when the signal is on while vhal_range
-    // is not provided.
-    float defaultTranslationValue;
-
-    // Default animation time elapsed to finish the texture operation.
-    // It is ignored if VHAL provides continuous signal value.
-    float animationTime;
-
-    // Physical translation range with start mapped to vhal_range start and
-    // end mapped to vhal_range end.
-    Range translationRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-};
-
-// Texture operation.
-struct TextureOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Texture operation type.
-    AnimationType type;
-
-    // Default texture id.
-    // It is used as default texture when the signal is on while vhal_range is
-    // not provided.
-    std::string defaultTexture;
-
-    // Default animation time elapsed to finish the texture operation.
-    // Unit is milliseconds.
-    // If the animation time is specified, the vhal_property is assumed to be
-    // on/off type.
-    // It is ignored if it is equal or less than zero and vhal_property is
-    // assumed to provide continuous value.
-    int animationTime;
-
-    // texture range mapped to texture_ids[i].first.
-    Range textureRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-
-    // Texture ids for switching textures.
-    // Applicable for animation types: kSwitchTextureOnce and
-    // kSwitchTextureRepeated
-    // 0 - n-1
-    std::vector<std::pair<float, std::string>> textureIds;
-};
-
-// Gamma operation.
-struct GammaOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Texture operation type.
-    // Applicable for animation types: kAdjustGammaOnce and kAdjustGammaRepeat.
-    AnimationType type;
-
-    // Default animation time elapsed to finish the gamma operation.
-    // Unit is milliseconds.
-    // If the animation time is specified, the vhal_property is assumed to be
-    // on/off type.
-    // It is ignored if it is equal or less than zero and vhal_property is
-    // assumed to provide continuous value.
-    int animationTime;
-
-    // Gamma range with start mapped to vhal_range start and
-    // end mapped to vhal_range end.
-    Range gammaRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-};
-
-// Animation info of a car part
-struct AnimationInfo {
-    // Car animation part id(name). It is a unique id.
-    std::string partId;
-
-    // Car part parent name.
-    std::string parentId;
-
-    // List of child Ids.
-    std::vector<std::string> childIds;
-
-    // Car part pose w.r.t parent's coordinate.
-    android_auto::surround_view::Mat4x4 pose;
-
-    // VHAL priority from high [0] to low [n-1]. Only VHALs specified in the
-    // vector have priority.
-    std::vector<uint64_t> vhalPriority;
-
-    // TODO(b/158245554): simplify xxOpsMap data structs.
-    // Map of gamma operations. Key value is VHAL property.
-    std::map<uint64_t, std::vector<GammaOp>> gammaOpsMap;
-
-    // Map of texture operations. Key value is VHAL property.
-    std::map<uint64_t, std::vector<TextureOp>> textureOpsMap;
-
-    // Map of rotation operations. Key value is VHAL property.
-    // Multiple rotation ops are supported and will be simultaneously animated in
-    // order if their rotation axis are different and rotation points are the
-    // same.
-    std::map<uint64_t, std::vector<RotationOp>> rotationOpsMap;
-
-    // Map of translation operations. Key value is VHAL property.
-    std::map<uint64_t, std::vector<TranslationOp>> translationOpsMap;
-};
-
-// Main struct in which surround view car model config is parsed into.
-struct AnimationConfig {
-    std::string version;
-
-    std::vector<AnimationInfo> animations;
-};
-
-// Car model.
-struct CarModel {
-    // Car model parts map.
-    std::map<std::string, android_auto::surround_view::CarPart> partsMap;
-
-    // Car testures map.
-    std::map<std::string, android_auto::surround_view::CarTexture> texturesMap;
-};
-
-struct CarModelConfig {
-    CarModel carModel;
-
-    AnimationConfig animationConfig;
-};
-
-struct IOModuleConfig {
-    // Camera config.
-    CameraConfig cameraConfig;
-
-    // Surround view 2d config.
-    SvConfig2d sv2dConfig;
-
-    // Surround view 3d config.
-    SvConfig3d sv3dConfig;
-
-    // Car model config.
-    CarModelConfig carModelConfig;
-};
-
-enum IOStatus : uint8_t {
-    // OK ststus. ALL fields read and parsed.
-    OK = 0,
-
-    // Error status. Cannot read the config file (config file missing or not
-    // accessible)
-    ERROR_READ_CONFIG_FILE = 1,
-
-    // Error ststus. Config file format doesn't match.
-    ERROR_CONFIG_FILE_FORMAT = 2,
-
-    // Warning status. Read car model (obj, mtl) error. Either the files are
-    // missing or wrong format.
-    ERROR_READ_CAR_MODEL = 3,
-
-    // Warning status. Read animation config file error. Either the file is
-    // missing or wrong format.
-    ERROR_READ_ANIMATION = 4,
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
diff --git a/cpp/surround_view/service-impl/MathHelp.h b/cpp/surround_view/service-impl/MathHelp.h
deleted file mode 100644
index 6623594..0000000
--- a/cpp/surround_view/service-impl/MathHelp.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_MATH_HELP_H_
-#define SURROUND_VIEW_SERVICE_IMPL_MATH_HELP_H_
-
-#include "Matrix4x4.h"
-#include "core_lib.h"
-
-#include <android-base/logging.h>
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using android_auto::surround_view::Mat4x4;
-
-const int gMat4Size = 4 * 4 * sizeof(float);
-
-const Mat4x4 gMat4Identity = {1, 0, 0, /*tx=*/0.0, 0, 1, 0, /*ty=*/0,
-                              0, 0, 1, /*tz=*/0.0, 0, 0, 0, 1};
-
-inline float degToRad(float angleInDegrees) {
-    return 1.0f * angleInDegrees / 180 * M_PI;
-}
-
-typedef std::array<float, 3> VectorT;
-typedef std::array<float, 4> HomVectorT;
-typedef Matrix4x4<float> HomMatrixT;
-
-// Create a Translation matrix.
-inline HomMatrixT translationMatrix(const VectorT& v) {
-    HomMatrixT m = HomMatrixT::identity();
-    m.setRow(3, HomVectorT{v[0], v[1], v[2], 1});
-    return m;
-}
-
-// Create a Rotation matrix.
-inline HomMatrixT rotationMatrix(const VectorT& v, float angle, int orientation) {
-    const float c = cos(angle);
-    const float s = orientation * sin(angle);
-    const float t = 1 - c;
-    const float tx = t * v[0];
-    const float ty = t * v[1];
-    const float tz = t * v[2];
-    return HomMatrixT(tx * v[0] + c, tx * v[1] + s * v[2], tx * v[2] - s * v[1], 0,
-                      tx * v[1] - s * v[2], ty * v[1] + c, ty * v[2] + s * v[0], 0,
-                      tx * v[2] + s * v[1], ty * v[2] - s * v[0], tz * v[2] + c, 0, 0, 0, 0, 1);
-}
-
-inline Mat4x4 toMat4x4(const Matrix4x4F& matrix4x4F) {
-    Mat4x4 mat4x4;
-    memcpy(&mat4x4[0], matrix4x4F.transpose().data(), gMat4Size);
-    return mat4x4;
-}
-
-inline Matrix4x4F toMatrix4x4F(const Mat4x4& mat4x4) {
-    Matrix4x4F matrix4x4F;
-    memcpy(matrix4x4F.data(), &mat4x4[0], gMat4Size);
-
-    for (int i = 0; i < 4; i++) {
-        for (int j = 0; j < 4; j++) {
-            if (matrix4x4F(i, j) != mat4x4[i * 4 + j]) {
-                LOG(ERROR) << "Matrix error";
-            }
-        }
-    }
-    return matrix4x4F.transpose();
-}
-
-// Create a Rotation Matrix, around a unit vector by a ccw angle.
-inline Mat4x4 rotationMatrix(float angleInDegrees, const VectorT& axis) {
-    return toMat4x4(rotationMatrix(axis, degToRad(angleInDegrees), 1));
-}
-
-inline Mat4x4 appendRotation(float angleInDegrees, const VectorT& axis, const Mat4x4& mat4) {
-    return toMat4x4(toMatrix4x4F(mat4) * rotationMatrix(axis, degToRad(angleInDegrees), 1));
-}
-
-// Append mat_l * mat_r;
-inline Mat4x4 appendMat(const Mat4x4& matL, const Mat4x4& matR) {
-    return toMat4x4(toMatrix4x4F(matL) * toMatrix4x4F(matR));
-}
-
-// Rotate about a point about a unit vector.
-inline Mat4x4 rotationAboutPoint(float angleInDegrees, const VectorT& point, const VectorT& axis) {
-    VectorT pointInv = point;
-    pointInv[0] *= -1;
-    pointInv[1] *= -1;
-    pointInv[2] *= -1;
-    return toMat4x4(translationMatrix(pointInv) *
-                    rotationMatrix(axis, degToRad(angleInDegrees), 1) * translationMatrix(point));
-}
-
-inline Mat4x4 translationMatrixToMat4x4(const VectorT& translation) {
-    return toMat4x4(translationMatrix(translation));
-}
-
-inline Mat4x4 appendTranslation(const VectorT& translation, const Mat4x4& mat4) {
-    return toMat4x4(toMatrix4x4F(mat4) * translationMatrix(translation));
-}
-
-inline Mat4x4 appendMatrix(const Mat4x4& deltaMatrix, const Mat4x4& currentMatrix) {
-    return toMat4x4(toMatrix4x4F(deltaMatrix) * toMatrix4x4F(currentMatrix));
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_MATH_HELP_H_
diff --git a/cpp/surround_view/service-impl/Matrix4x4.h b/cpp/surround_view/service-impl/Matrix4x4.h
deleted file mode 100644
index 8854e69..0000000
--- a/cpp/surround_view/service-impl/Matrix4x4.h
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_MATRIX4X4_H_
-#define SURROUND_VIEW_SERVICE_IMPL_MATRIX4X4_H_
-
-#include <array>
-#include <cassert>
-#include <cmath>
-#include <iosfwd>
-
-template <class VType>
-class Matrix4x4 {
-private:
-    VType m[4][4];
-
-public:
-    typedef Matrix4x4<VType> Self;
-    typedef VType BaseType;
-    typedef std::array<VType, 4> MVector;
-
-    // Initialize the matrix to 0
-    Matrix4x4() {
-        m[0][3] = m[0][2] = m[0][1] = m[0][0] = VType();
-        m[1][3] = m[1][2] = m[1][1] = m[1][0] = VType();
-        m[2][3] = m[2][2] = m[2][1] = m[2][0] = VType();
-        m[3][3] = m[3][2] = m[3][1] = m[3][0] = VType();
-    }
-
-    // Explicitly set every element on construction
-    Matrix4x4(const VType& m00, const VType& m01, const VType& m02, const VType& m03,
-              const VType& m10, const VType& m11, const VType& m12, const VType& m13,
-              const VType& m20, const VType& m21, const VType& m22, const VType& m23,
-              const VType& m30, const VType& m31, const VType& m32, const VType& m33) {
-        m[0][0] = m00;
-        m[0][1] = m01;
-        m[0][2] = m02;
-        m[0][3] = m03;
-
-        m[1][0] = m10;
-        m[1][1] = m11;
-        m[1][2] = m12;
-        m[1][3] = m13;
-
-        m[2][0] = m20;
-        m[2][1] = m21;
-        m[2][2] = m22;
-        m[2][3] = m23;
-
-        m[3][0] = m30;
-        m[3][1] = m31;
-        m[3][2] = m32;
-        m[3][3] = m33;
-    }
-
-    // Casting constructor
-    template <class VType2>
-    static Matrix4x4 cast(const Matrix4x4<VType2>& mb) {
-        return Matrix4x4(static_cast<VType>(mb(0, 0)), static_cast<VType>(mb(0, 1)),
-                         static_cast<VType>(mb(0, 2)), static_cast<VType>(mb(0, 3)),
-                         static_cast<VType>(mb(1, 0)), static_cast<VType>(mb(1, 1)),
-                         static_cast<VType>(mb(1, 2)), static_cast<VType>(mb(1, 3)),
-                         static_cast<VType>(mb(2, 0)), static_cast<VType>(mb(2, 1)),
-                         static_cast<VType>(mb(2, 2)), static_cast<VType>(mb(2, 3)),
-                         static_cast<VType>(mb(3, 0)), static_cast<VType>(mb(3, 1)),
-                         static_cast<VType>(mb(3, 2)), static_cast<VType>(mb(3, 3)));
-    }
-
-    // Change the value of all the coefficients of the matrix
-    inline Matrix4x4& set(const VType& m00, const VType& m01, const VType& m02, const VType& m03,
-                          const VType& m10, const VType& m11, const VType& m12, const VType& m13,
-                          const VType& m20, const VType& m21, const VType& m22, const VType& m23,
-                          const VType& m30, const VType& m31, const VType& m32, const VType& m33) {
-        m[0][0] = m00;
-        m[0][1] = m01;
-        m[0][2] = m02;
-        m[0][3] = m03;
-
-        m[1][0] = m10;
-        m[1][1] = m11;
-        m[1][2] = m12;
-        m[1][3] = m13;
-
-        m[2][0] = m20;
-        m[2][1] = m21;
-        m[2][2] = m22;
-        m[2][3] = m23;
-
-        m[3][0] = m30;
-        m[3][1] = m31;
-        m[3][2] = m32;
-        m[3][3] = m33;
-        return (*this);
-    }
-
-    // Matrix addition
-    inline Matrix4x4& operator+=(const Matrix4x4& addFrom) {
-        m[0][0] += addFrom.m[0][0];
-        m[0][1] += addFrom.m[0][1];
-        m[0][2] += addFrom.m[0][2];
-        m[0][3] += addFrom.m[0][3];
-
-        m[1][0] += addFrom.m[1][0];
-        m[1][1] += addFrom.m[1][1];
-        m[1][2] += addFrom.m[1][2];
-        m[1][3] += addFrom.m[1][3];
-
-        m[2][0] += addFrom.m[2][0];
-        m[2][1] += addFrom.m[2][1];
-        m[2][2] += addFrom.m[2][2];
-        m[2][3] += addFrom.m[2][3];
-
-        m[3][0] += addFrom.m[3][0];
-        m[3][1] += addFrom.m[3][1];
-        m[3][2] += addFrom.m[3][2];
-        m[3][3] += addFrom.m[3][3];
-        return (*this);
-    }
-
-    // Matrix subtration
-    inline Matrix4x4& operator-=(const Matrix4x4& subFrom) {
-        m[0][0] -= subFrom.m[0][0];
-        m[0][1] -= subFrom.m[0][1];
-        m[0][2] -= subFrom.m[0][2];
-        m[0][3] -= subFrom.m[0][3];
-
-        m[1][0] -= subFrom.m[1][0];
-        m[1][1] -= subFrom.m[1][1];
-        m[1][2] -= subFrom.m[1][2];
-        m[1][3] -= subFrom.m[1][3];
-
-        m[2][0] -= subFrom.m[2][0];
-        m[2][1] -= subFrom.m[2][1];
-        m[2][2] -= subFrom.m[2][2];
-        m[2][3] -= subFrom.m[2][3];
-
-        m[3][0] -= subFrom.m[3][0];
-        m[3][1] -= subFrom.m[3][1];
-        m[3][2] -= subFrom.m[3][2];
-        m[3][3] -= subFrom.m[3][3];
-        return (*this);
-    }
-
-    // Matrix multiplication by a scalar
-    inline Matrix4x4& operator*=(const VType& k) {
-        m[0][0] *= k;
-        m[0][1] *= k;
-        m[0][2] *= k;
-        m[0][3] *= k;
-
-        m[1][0] *= k;
-        m[1][1] *= k;
-        m[1][2] *= k;
-        m[1][3] *= k;
-
-        m[2][0] *= k;
-        m[2][1] *= k;
-        m[2][2] *= k;
-        m[2][3] *= k;
-
-        m[3][0] *= k;
-        m[3][1] *= k;
-        m[3][2] *= k;
-        m[3][3] *= k;
-        return (*this);
-    }
-
-    // Matrix addition
-    inline Matrix4x4 operator+(const Matrix4x4& mb) const { return Matrix4x4(*this) += mb; }
-
-    // Matrix subtraction
-    inline Matrix4x4 operator-(const Matrix4x4& mb) const { return Matrix4x4(*this) -= mb; }
-
-    // Change the sign of all the coefficients in the matrix
-    friend inline Matrix4x4 operator-(const Matrix4x4& vb) {
-        return Matrix4x4(-vb.m[0][0], -vb.m[0][1], -vb.m[0][2], -vb.m[0][3], -vb.m[1][0],
-                         -vb.m[1][1], -vb.m[1][2], -vb.m[1][3], -vb.m[2][0], -vb.m[2][1],
-                         -vb.m[2][2], -vb.m[2][3], -vb.m[3][0], -vb.m[3][1], -vb.m[3][2],
-                         -vb.m[3][3]);
-    }
-
-    // Matrix multiplication by a scalar
-    inline Matrix4x4 operator*(const VType& k) const { return Matrix4x4(*this) *= k; }
-
-    // Multiplication by a scaler
-    friend inline Matrix4x4 operator*(const VType& k, const Matrix4x4& mb) {
-        return Matrix4x4(mb) * k;
-    }
-
-    // Matrix multiplication
-    friend Matrix4x4 operator*(const Matrix4x4& a, const Matrix4x4& b) {
-        return Matrix4x4::fromCols(a * b.col(0), a * b.col(1), a * b.col(2), a * b.col(3));
-    }
-
-    // Multiplication of a matrix by a vector
-    friend MVector operator*(const Matrix4x4& a, const MVector& b) {
-        return MVector{dotProd(a.row(0), b), dotProd(a.row(1), b), dotProd(a.row(2), b),
-                       dotProd(a.row(3), b)};
-    }
-
-    // Return the trace of the matrix
-    inline VType trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; }
-
-    // Return a pointer to the data array for interface with other libraries
-    // like opencv
-    VType* data() { return reinterpret_cast<VType*>(m); }
-    const VType* data() const { return reinterpret_cast<const VType*>(m); }
-
-    // Return matrix element (i,j) with 0<=i<=3 0<=j<=3
-    inline VType& operator()(const int i, const int j) {
-        assert(i >= 0);
-        assert(i < 4);
-        assert(j >= 0);
-        assert(j < 4);
-        return m[i][j];
-    }
-
-    inline VType operator()(const int i, const int j) const {
-        assert(i >= 0);
-        assert(i < 4);
-        assert(j >= 0);
-        assert(j < 4);
-        return m[i][j];
-    }
-
-    // Return matrix element (i/4,i%4) with 0<=i<=15 (access concatenated rows).
-    inline VType& operator[](const int i) {
-        assert(i >= 0);
-        assert(i < 16);
-        return reinterpret_cast<VType*>(m)[i];
-    }
-    inline VType operator[](const int i) const {
-        assert(i >= 0);
-        assert(i < 16);
-        return reinterpret_cast<const VType*>(m)[i];
-    }
-
-    // Return the transposed matrix
-    inline Matrix4x4 transpose() const {
-        return Matrix4x4(m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1],
-                         m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3]);
-    }
-
-    // Returns the transpose of the matrix of the cofactors.
-    // (Useful for inversion for example.)
-    inline Matrix4x4 comatrixTransposed() const {
-        const auto cof = [this](unsigned int row, unsigned int col) {
-            unsigned int r0 = (row + 1) % 4;
-            unsigned int r1 = (row + 2) % 4;
-            unsigned int r2 = (row + 3) % 4;
-            unsigned int c0 = (col + 1) % 4;
-            unsigned int c1 = (col + 2) % 4;
-            unsigned int c2 = (col + 3) % 4;
-
-            VType minor = m[r0][c0] * (m[r1][c1] * m[r2][c2] - m[r2][c1] * m[r1][c2]) -
-                    m[r1][c0] * (m[r0][c1] * m[r2][c2] - m[r2][c1] * m[r0][c2]) +
-                    m[r2][c0] * (m[r0][c1] * m[r1][c2] - m[r1][c1] * m[r0][c2]);
-            return (row + col) & 1 ? -minor : minor;
-        };
-
-        // Transpose
-        return Matrix4x4(cof(0, 0), cof(1, 0), cof(2, 0), cof(3, 0), cof(0, 1), cof(1, 1),
-                         cof(2, 1), cof(3, 1), cof(0, 2), cof(1, 2), cof(2, 2), cof(3, 2),
-                         cof(0, 3), cof(1, 3), cof(2, 3), cof(3, 3));
-    }
-
-    // Return dot production of two the vectors
-    static inline VType dotProd(const MVector& lhs, const MVector& rhs) {
-        return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2] + lhs[3] * rhs[3];
-    }
-
-    // Return the 4D vector at row i
-    inline MVector row(const int i) const {
-        assert(i >= 0);
-        assert(i < 4);
-        return MVector{m[i][0], m[i][1], m[i][2], m[i][3]};
-    }
-
-    // Return the 4D vector at col i
-    inline MVector col(const int i) const {
-        assert(i >= 0);
-        assert(i < 4);
-        return MVector{m[0][i], m[1][i], m[2][i], m[3][i]};
-    }
-
-    // Create a matrix from 4 row vectors
-    static inline Matrix4x4 fromRows(const MVector& v1, const MVector& v2, const MVector& v3,
-                                     const MVector& v4) {
-        return Matrix4x4(v1[0], v1[1], v1[2], v1[3], v2[0], v2[1], v2[2], v2[3], v3[0], v3[1],
-                         v3[2], v3[3], v4[0], v4[1], v4[2], v4[3]);
-    }
-
-    // Create a matrix from 3 column vectors
-    static inline Matrix4x4 fromCols(const MVector& v1, const MVector& v2, const MVector& v3,
-                                     const MVector& v4) {
-        return Matrix4x4(v1[0], v2[0], v3[0], v4[0], v1[1], v2[1], v3[1], v4[1], v1[2], v2[2],
-                         v3[2], v4[2], v1[3], v2[3], v3[3], v4[3]);
-    }
-
-    // Set the vector in row i to be v1
-    void setRow(int i, const MVector& v1) {
-        assert(i >= 0);
-        assert(i < 4);
-        m[i][0] = v1[0];
-        m[i][1] = v1[1];
-        m[i][2] = v1[2];
-        m[i][3] = v1[3];
-    }
-
-    // Set the vector in column i to be v1
-    void setCol(int i, const MVector& v1) {
-        assert(i >= 0);
-        assert(i < 4);
-        m[0][i] = v1[0];
-        m[1][i] = v1[1];
-        m[2][i] = v1[2];
-        m[3][i] = v1[3];
-    }
-
-    // Return the identity matrix
-    static inline Matrix4x4 identity() {
-        return Matrix4x4(VType(1), VType(), VType(), VType(), VType(), VType(1), VType(), VType(),
-                         VType(), VType(), VType(1), VType(), VType(), VType(), VType(), VType(1));
-    }
-
-    // Return a matrix full of zeros
-    static inline Matrix4x4 zero() { return Matrix4x4(); }
-
-    // Return a diagonal matrix with the coefficients in v
-    static inline Matrix4x4 diagonal(const MVector& v) {
-        return Matrix4x4(v[0], VType(), VType(), VType(),  //
-                         VType(), v[1], VType(), VType(),  //
-                         VType(), VType(), v[2], VType(),  //
-                         VType(), VType(), VType(), v[3]);
-    }
-
-    // Return the matrix vvT
-    static Matrix4x4 sym4(const MVector& v) {
-        return Matrix4x4(v[0] * v[0], v[0] * v[1], v[0] * v[2], v[0] * v[3], v[1] * v[0],
-                         v[1] * v[1], v[1] * v[2], v[1] * v[3], v[2] * v[0], v[2] * v[1],
-                         v[2] * v[2], v[2] * v[3], v[3] * v[0], v[3] * v[1], v[3] * v[2],
-                         v[3] * v[3]);
-    }
-
-    // Return the Frobenius norm of the matrix: sqrt(sum(aij^2))
-    VType frobeniusNorm() const {
-        VType sum = VType();
-        for (int i = 0; i < 4; i++) {
-            for (int j = 0; j < 4; j++) {
-                sum += m[i][j] * m[i][j];
-            }
-        }
-        return std::sqrt(sum);
-    }
-
-    // Return true is one of the elements of the matrix is NaN
-    bool isNaN() const {
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 4; ++j) {
-                if (isnan(m[i][j])) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    friend bool operator==(const Matrix4x4& a, const Matrix4x4& b) {
-        return a.m[0][0] == b.m[0][0] && a.m[0][1] == b.m[0][1] && a.m[0][2] == b.m[0][2] &&
-                a.m[0][3] == b.m[0][3] && a.m[1][0] == b.m[1][0] && a.m[1][1] == b.m[1][1] &&
-                a.m[1][2] == b.m[1][2] && a.m[1][3] == b.m[1][3] && a.m[2][0] == b.m[2][0] &&
-                a.m[2][1] == b.m[2][1] && a.m[2][2] == b.m[2][2] && a.m[2][3] == b.m[2][3] &&
-                a.m[3][0] == b.m[3][0] && a.m[3][1] == b.m[3][1] && a.m[3][2] == b.m[3][2] &&
-                a.m[3][3] == b.m[3][3];
-    }
-
-    friend bool operator!=(const Matrix4x4& a, const Matrix4x4& b) { return !(a == b); }
-};
-
-typedef Matrix4x4<int> Matrix4x4I;
-typedef Matrix4x4<float> Matrix4x4F;
-typedef Matrix4x4<double> Matrix4x4D;
-
-#endif  // #ifndef SURROUND_VIEW_SERVICE_IMPL_MATRIX4X4_H_
diff --git a/cpp/surround_view/service-impl/MtlReader.cpp b/cpp/surround_view/service-impl/MtlReader.cpp
deleted file mode 100644
index 7caccec..0000000
--- a/cpp/surround_view/service-impl/MtlReader.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "MtlReader.h"
-
-#include <android-base/logging.h>
-#include <cstdio>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-namespace {
-
-constexpr int kCharBufferSize = 128;
-
-void ReadFloat3(FILE* file, float* value) {
-    float temp[3];
-    int res = fscanf(file, "%f %f %f", &temp[0], &temp[1], &temp[2]);
-    3 == res ? std::memcpy(value, temp, 3 * sizeof(float)) : nullptr;
-}
-
-void ReadFloat(FILE* file, float* value) {
-    float temp;
-    int res = fscanf(file, "%f", &temp);
-    *value = res > 0 ? temp : -1;
-}
-
-void ReadInt(FILE* file, int* value) {
-    int temp;
-    int res = fscanf(file, "%d", &temp);
-    *value = res > 0 ? temp : -1;
-}
-
-void ReadString(FILE* file, std::string* value) {
-    char temp[kCharBufferSize];
-    fscanf(file, "%s", temp);
-    *value = temp;
-}
-}  // namespace
-
-bool ReadMtlFromFile(const std::string& mtlFilename,
-                     std::map<std::string, MtlConfigParams>* params) {
-    FILE* file = fopen(mtlFilename.c_str(), "r");
-    if (!file) {
-        LOG(ERROR) << "Failed to open mtl file: " << mtlFilename;
-        return false;
-    }
-
-    std::string currentConfig;
-    while (true) {
-        char lineHeader[kCharBufferSize];
-        // read the first word of the line
-        int res = fscanf(file, "%s", lineHeader);
-
-        if (res == EOF) {
-            break;  // EOF = End Of File. Quit the loop.
-        }
-
-        if (strcmp(lineHeader, "#") == 0) {
-            fgets(lineHeader, sizeof(lineHeader), file);
-            continue;
-        }
-        if (strcmp(lineHeader, "newmtl") == 0) {
-            res = fscanf(file, "%s", lineHeader);
-            if (params->find(lineHeader) != params->end()) {
-                fclose(file);
-                LOG(ERROR) << "Duplicated params of : " << lineHeader[0];
-                return false;
-            }
-            currentConfig = lineHeader;
-            continue;
-        }
-
-        if (strcmp(lineHeader, "Ns") == 0) {
-            ReadFloat(file, &((*params)[currentConfig].ns));
-            continue;
-        }
-        if (strcmp(lineHeader, "Ni") == 0) {
-            ReadFloat(file, &((*params)[currentConfig].ni));
-            continue;
-        }
-        if (strcmp(lineHeader, "d") == 0) {
-            ReadFloat(file, &((*params)[currentConfig].d));
-            continue;
-        }
-        if (strcmp(lineHeader, "Tr") == 0) {
-            ReadFloat(file, &((*params)[currentConfig].tr));
-            continue;
-        }
-        if (strcmp(lineHeader, "Tf") == 0) {
-            ReadFloat3(file, (*params)[currentConfig].tf);
-            continue;
-        }
-        if (strcmp(lineHeader, "illum") == 0) {
-            ReadInt(file, &((*params)[currentConfig].illum));
-            continue;
-        }
-        if (strcmp(lineHeader, "Ka") == 0) {
-            ReadFloat3(file, (*params)[currentConfig].ka);
-            continue;
-        }
-        if (strcmp(lineHeader, "Kd") == 0) {
-            ReadFloat3(file, (*params)[currentConfig].kd);
-            continue;
-        }
-        if (strcmp(lineHeader, "Ks") == 0) {
-            ReadFloat3(file, (*params)[currentConfig].ks);
-            continue;
-        }
-        if (strcmp(lineHeader, "Ke") == 0) {
-            ReadFloat3(file, (*params)[currentConfig].ke);
-            continue;
-        }
-        if (strcmp(lineHeader, "map_bump") == 0) {
-            ReadString(file, &((*params)[currentConfig].mapBump));
-            continue;
-        }
-        if (strcmp(lineHeader, "bump") == 0) {
-            ReadString(file, &((*params)[currentConfig].bump));
-            continue;
-        }
-        if (strcmp(lineHeader, "map_Ka") == 0) {
-            ReadString(file, &((*params)[currentConfig].mapKa));
-            continue;
-        }
-        if (strcmp(lineHeader, "map_Kd") == 0) {
-            ReadString(file, &((*params)[currentConfig].mapKd));
-            continue;
-        }
-        if (strcmp(lineHeader, "map_Ks") == 0) {
-            ReadString(file, &((*params)[currentConfig].mapKs));
-            continue;
-        } else {
-            LOG(WARNING) << "Unknown tag " << lineHeader << ". Skipped";
-            fgets(lineHeader, sizeof(lineHeader), file);
-            continue;
-        }
-    }
-
-    fclose(file);
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/MtlReader.h b/cpp/surround_view/service-impl/MtlReader.h
deleted file mode 100644
index 3e19876..0000000
--- a/cpp/surround_view/service-impl/MtlReader.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
-#define SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
-
-#include <map>
-#include <string>
-
-#include "core_lib.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Mtl defined params.
-struct MtlConfigParams {
-    // Ns exponent
-    // Specifies the specular exponent for the current material. This defines
-    // the focus of the specular highlight.
-    // Ns values normally range from 0 to 1000.
-    float ns = -1;
-
-    // optical_density
-    // Specifies the optical density for the surface. This is also known as
-    // index of refraction.
-    //  "optical_density" is the value for the optical density. The values can
-    // range from 0.001 to 10. A value of 1.0 means that light does not bend
-    // as it passes through an object. Increasing the optical_density
-    // increases the amount of bending. Glass has an index of refraction of
-    // about 1.5.  Values of less than 1.0 produce bizarre results and are not
-    // recommended.
-    float ni = -1;
-
-    // d defines the non-transparency of the material to be alpha.
-    // The default is 1.0 (not transparent at all).
-    // The quantities d and Tr are the opposites of each other.
-    float d = -1;
-
-    // The Tr statement specifies the transparency of the material to be alpha.
-    // The default is 0.0 (not transparent at all).
-    // The quantities d and Tr are the opposites of each other,
-    float tr = -1;
-
-    // The Tf statement specifies the transmission filter using RGB values.
-    // "r g b" are the values for the red, green, and blue components of the
-    // atmosphere.  The g and b arguments are optional. If only r is
-    // specified, then g, and b are assumed to be equal to r. The r g b values
-    // are normally in the range of 0.0 to 1.0. Values outside this range
-    // increase or decrease the relectivity accordingly.
-    float tf[3] = {-1, -1, -1};
-
-    // illum_#
-    // The "illum" statement specifies the illumination model to use in the
-    // material.  Illumination models are mathematical equations that represent
-    // various material lighting and shading effects.
-    //
-    // "illum_#"can be a number from 0 to 10. The illumination models are
-    // summarized below;
-    //
-    //  Illumination    Properties that are turned on in the
-    //  model           Property Editor
-    //
-    //  0 Color on and Ambient off
-    //  1 Color on and Ambient on
-    //  2 Highlight on
-    //  3 Reflection on and Ray trace on
-    //  4 Transparency: Glass on
-    //    Reflection: Ray trace on
-    //  5 Reflection: Fresnel on and Ray trace on
-    //  6 Transparency: Refraction on
-    //    Reflection: Fresnel off and Ray trace on
-    //  7 Transparency: Refraction on
-    //    Reflection: Fresnel on and Ray trace on
-    //  8 Reflection on and Ray trace off
-    //  9 Transparency: Glass on
-    //    Reflection: Ray trace off
-    // 10 Casts shadows onto invisible surfaces
-    int illum = -1;
-
-    // The Ka statement specifies the ambient reflectivity using RGB values.
-    // "r g b" are the values for the red, green, and blue components of the
-    // color.  The g and b arguments are optional. If only r is specified,
-    // then g, and b are assumed to be equal to r. The r g b values are
-    // normally in the range of 0.0 to 1.0. Values outside this range increase
-    // or decrease the relectivity accordingly.
-    float ka[3] = {-1, -1, -1};
-
-    // The Kd statement specifies the diffuse reflectivity using RGB values.
-    //  "r g b" are the values for the red, green, and blue components of the
-    // atmosphere.  The g and b arguments are optional.  If only r is
-    // specified, then g, and b are assumed to be equal to r. The r g b values
-    // are normally in the range of 0.0 to 1.0. Values outside this range
-    // increase or decrease the relectivity accordingly.
-    float kd[3] = {-1, -1, -1};
-
-    // The Ks statement specifies the specular reflectivity using RGB values.
-    //  "r g b" are the values for the red, green, and blue components of the
-    // atmosphere. The g and b arguments are optional. If only r is
-    // specified, then g, and b are assumed to be equal to r. The r g b values
-    // are normally in the range of 0.0 to 1.0. Values outside this range
-    // increase or decrease the relectivity accordingly.
-    float ks[3] = {-1, -1, -1};
-
-    // Emissive coeficient. It goes together with ambient, diffuse and specular
-    // and represents the amount of light emitted by the material.
-    float ke[3] = {-1, -1, -1};
-
-    // Specifies that a color texture file or color procedural texture file is
-    // linked to the specular reflectivity of the material. During rendering,
-    // the map_Ks value is multiplied by the Ks value.
-    std::string mapKs;
-
-    // Specifies that a color texture file or a color procedural texture file
-    // is applied to the ambient reflectivity of the material. During
-    // rendering, the "map_Ka" value is multiplied by the "Ka" value.
-    std::string mapKa;
-
-    // Specifies that a color texture file or color procedural texture file is
-    // linked to the diffuse reflectivity of the material. During rendering,
-    // the map_Kd value is multiplied by the Kd value.
-    std::string mapKd;
-
-    // Same as bump
-    std::string mapBump;
-
-    // Specifies that a bump texture file or a bump procedural texture file is
-    // linked to the material.
-    std::string bump;
-
-    MtlConfigParams& operator=(const MtlConfigParams& rhs) {
-        ns = rhs.ns;
-        ni = rhs.ni;
-        d = rhs.d;
-        tr = rhs.tr;
-        std::memcpy(tf, rhs.tf, 3 * sizeof(float));
-        illum = rhs.illum;
-        std::memcpy(ka, rhs.ka, 3 * sizeof(float));
-        std::memcpy(kd, rhs.kd, 3 * sizeof(float));
-        std::memcpy(ks, rhs.ks, 3 * sizeof(float));
-        std::memcpy(ke, rhs.ke, 3 * sizeof(float));
-        mapKs = rhs.mapKs;
-        mapKa = rhs.mapKa;
-        mapKd = rhs.mapKd;
-        mapBump = rhs.mapBump;
-        bump = rhs.bump;
-
-        return *this;
-    }
-};
-
-// Reads mtl file associated with obj file.
-// |filename| is the full path and name of the obj file.
-bool ReadMtlFromFile(const std::string& mtlFilename,
-                     std::map<std::string, MtlConfigParams>* params);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_MTLREADER_H_
diff --git a/cpp/surround_view/service-impl/ObjReader.cpp b/cpp/surround_view/service-impl/ObjReader.cpp
deleted file mode 100644
index dcb1973..0000000
--- a/cpp/surround_view/service-impl/ObjReader.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "ObjReader.h"
-
-#include <array>
-#include <cstdio>
-#include <filesystem>
-#include <vector>
-
-#include "MtlReader.h"
-#include "core_lib.h"
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using android_auto::surround_view::CarMaterial;
-using android_auto::surround_view::CarVertex;
-
-namespace {
-
-constexpr int kNumberOfVerticesPerFace = 3;
-constexpr int kNumberOfAxes = 3;
-constexpr int kCharBufferSize = 128;
-
-const std::array<float, 16> kMat4Identity = {
-        /*row 0*/ 1, 0, 0, 0,
-        /*row 1*/ 0, 1, 0, 0,
-        /*row 2*/ 0, 0, 1, 0,
-        /*row 3*/ 0, 0, 0, 1};
-
-// Copies face vertices parsed from obj to car vertices.
-void CopyFaceToCarVertex(const std::vector<std::array<float, kNumberOfAxes>>& currentVertices,
-                         const std::vector<std::array<float, kNumberOfAxes>>& currentTextures,
-                         const std::vector<std::array<float, kNumberOfAxes>>& currentNormals,
-                         int vertexId, int textureId, int normalId, CarVertex* carVertex) {
-    std::memcpy(carVertex->pos.data(), currentVertices[vertexId - 1].data(),
-                currentVertices[vertexId - 1].size() * sizeof(float));
-
-    if (textureId != -1) {
-        std::memcpy(carVertex->tex_coord.data(), currentTextures[textureId - 1].data(),
-                    2 * sizeof(float));
-        // Set texture coodinates as invalid.
-        carVertex->tex_coord = {-1.0, -1.0};
-    }
-
-    std::memcpy(carVertex->normal.data(), currentNormals[normalId - 1].data(),
-                currentNormals[normalId - 1].size() * sizeof(float));
-}
-
-}  // namespace
-
-bool ReadObjFromFile(const std::string& objFilename, std::map<std::string, CarPart>* carPartsMap) {
-    return ReadObjFromFile(objFilename, ReadObjOptions(), carPartsMap);
-}
-
-bool ReadObjFromFile(const std::string& objFilename, const ReadObjOptions& option,
-                     std::map<std::string, CarPart>* carPartsMap) {
-    FILE* file = fopen(objFilename.c_str(), "r");
-    if (!file) {
-        LOG(ERROR) << "Failed to open obj file: " << objFilename;
-        return false;
-    }
-
-    for (int i = 0; i < kNumberOfAxes; ++i) {
-        if (option.coordinateMapping[i] >= kNumberOfAxes || option.coordinateMapping[i] < 0) {
-            fclose(file);
-            LOG(ERROR) << "coordinateMapping index must be less than 3 and greater or equal "
-                          "to 0.";
-            return false;
-        }
-    }
-
-    std::vector<std::array<float, kNumberOfAxes>> currentVertices;
-    std::vector<std::array<float, kNumberOfAxes>> currentNormals;
-    std::vector<std::array<float, kNumberOfAxes>> currentTextures;
-    std::map<std::string, MtlConfigParams> mtlConfigParamsMap;
-    std::string currentGroupName;
-    MtlConfigParams currentMtlConfig;
-
-    while (true) {
-        char lineHeader[kCharBufferSize];
-        // read the first word of the line
-        int res = fscanf(file, "%s", lineHeader);
-
-        if (res == EOF) {
-            break;  // EOF = End Of File. Quit the loop.
-        }
-        if (strcmp(lineHeader, "#") == 0) {
-            fgets(lineHeader, sizeof(lineHeader), file);
-            continue;
-        }
-
-        // TODO(b/156558814): add object type support.
-        // TODO(b/156559272): add document for supported format.
-        // Only single group per line is supported.
-        if (strcmp(lineHeader, "g") == 0) {
-            res = fscanf(file, "%s", lineHeader);
-            currentGroupName = lineHeader;
-            currentMtlConfig = MtlConfigParams();
-
-            if (carPartsMap->find(currentGroupName) != carPartsMap->end()) {
-                LOG(WARNING) << "Duplicate group name: " << currentGroupName
-                             << ". using car part name as: " << currentGroupName << "_dup";
-                currentGroupName.append("_dup");
-            }
-            carPartsMap->emplace(
-                    std::make_pair(currentGroupName,
-                                   CarPart((std::vector<CarVertex>()), CarMaterial(), kMat4Identity,
-                                           std::string(), std::vector<std::string>())));
-            continue;
-        }
-
-        // no "g" case, assign it as default.
-        if (currentGroupName.empty()) {
-            currentGroupName = "default";
-            currentMtlConfig = MtlConfigParams();
-            carPartsMap->emplace(
-                    std::make_pair(currentGroupName,
-                                   CarPart((std::vector<CarVertex>()), CarMaterial(), kMat4Identity,
-                                           std::string(), std::vector<std::string>())));
-        }
-
-        if (strcmp(lineHeader, "usemtl") == 0) {
-            res = fscanf(file, "%s", lineHeader);
-
-            // If material name not found.
-            if (mtlConfigParamsMap.find(lineHeader) == mtlConfigParamsMap.end()) {
-                carPartsMap->at(currentGroupName).material = CarMaterial();
-                LOG(ERROR) << "Material not found: $0" << lineHeader;
-                return false;
-            }
-
-            currentMtlConfig = mtlConfigParamsMap[lineHeader];
-
-            carPartsMap->at(currentGroupName).material.ka = {currentMtlConfig.ka[0],
-                                                             currentMtlConfig.ka[1],
-                                                             currentMtlConfig.ka[2]};
-
-            carPartsMap->at(currentGroupName).material.kd = {currentMtlConfig.kd[0],
-                                                             currentMtlConfig.kd[1],
-                                                             currentMtlConfig.kd[2]};
-
-            carPartsMap->at(currentGroupName).material.ks = {currentMtlConfig.ks[0],
-                                                             currentMtlConfig.ks[1],
-                                                             currentMtlConfig.ks[2]};
-
-            carPartsMap->at(currentGroupName).material.d = currentMtlConfig.d;
-
-            carPartsMap->at(currentGroupName).material.textures.clear();
-
-            continue;
-        }
-
-        if (strcmp(lineHeader, "mtllib") == 0) {
-            res = fscanf(file, "%s", lineHeader);
-            mtlConfigParamsMap.clear();
-            std::string mtlFilename;
-            if (option.mtlFilename.empty()) {
-                mtlFilename = objFilename.substr(0, objFilename.find_last_of("/"));
-                mtlFilename.append("/");
-                mtlFilename.append(lineHeader);
-            } else {
-                mtlFilename = option.mtlFilename;
-            }
-            if (!ReadMtlFromFile(mtlFilename, &mtlConfigParamsMap)) {
-                LOG(ERROR) << "Parse MTL file " << mtlFilename << " failed.";
-                return false;
-            }
-            continue;
-        }
-
-        if (strcmp(lineHeader, "v") == 0) {
-            std::array<float, kNumberOfAxes> pos;
-            fscanf(file, "%f %f %f\n", &pos[option.coordinateMapping[0]],
-                   &pos[option.coordinateMapping[1]], &pos[option.coordinateMapping[2]]);
-            for (int i = 0; i < kNumberOfAxes; ++i) {
-                pos[i] *= option.scales[i];
-                pos[i] += option.offsets[i];
-            }
-            currentVertices.push_back(pos);
-        } else if (strcmp(lineHeader, "vt") == 0) {
-            std::array<float, kNumberOfAxes> texture;
-            fscanf(file, "%f %f %f\n", &texture[0], &texture[1], &texture[2]);
-            currentTextures.push_back(texture);
-        } else if (strcmp(lineHeader, "vn") == 0) {
-            std::array<float, kNumberOfAxes> normal;
-            fscanf(file, "%f %f %f\n", &normal[option.coordinateMapping[0]],
-                   &normal[option.coordinateMapping[1]], &normal[option.coordinateMapping[2]]);
-            currentNormals.push_back(normal);
-        } else if (strcmp(lineHeader, "f") == 0) {
-            int vertexId[kNumberOfVerticesPerFace];
-            int textureId[kNumberOfVerticesPerFace] = {-1, -1, -1};
-            int normalId[kNumberOfVerticesPerFace];
-
-            // Face vertices supported formats:
-            // With texture:     pos/texture/normal
-            // Without texture:  pos//normal
-
-            // Scan first vertex position.
-            int matches = fscanf(file, "%d/", &vertexId[0]);
-
-            if (matches != 1) {
-                LOG(WARNING) << "Face index error. Skipped.";
-                fgets(lineHeader, sizeof(lineHeader), file);
-                continue;
-            }
-
-            // Try scanning first two face 2 vertices with texture format present.
-            bool isTexturePresent = true;
-            matches = fscanf(file, "%d/%d %d/%d/%d", &textureId[0], &normalId[0], &vertexId[1],
-                             &textureId[1], &normalId[1]);
-
-            // If 5 matches not found, try scanning first 2 face vertices without
-            // texture format.
-            if (matches != 5) {
-                matches = fscanf(file, "/%d %d//%d", &normalId[0], &vertexId[1], &normalId[1]);
-
-                // If 3 matches not found return with error.
-                if (matches != 3) {
-                    LOG(WARNING) << "Face format not supported. Skipped.";
-                    fgets(lineHeader, sizeof(lineHeader), file);
-                    continue;
-                }
-
-                isTexturePresent = false;
-            }
-
-            // Copy first two face vertices to car vertices.
-            std::array<CarVertex, kNumberOfVerticesPerFace> carVertices;
-            CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[0],
-                                textureId[0], normalId[0], &carVertices[0]);
-            CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[1],
-                                textureId[1], normalId[1], &carVertices[1]);
-
-            // Add a triangle that the first two vertices make with every subsequent
-            // face vertex 3 and onwards. Note this assumes the face is a convex
-            // polygon.
-            do {
-                if (isTexturePresent) {
-                    matches = fscanf(file, " %d/%d/%d", &vertexId[2], &textureId[2], &normalId[2]);
-                    // Warn if un-expected number of matches.
-                    if (matches != 3 && matches != 0) {
-                        LOG(WARNING) << "Face matches, expected 3, read: " << matches;
-                        break;
-                    }
-                } else {
-                    // Warn if un-expected number of matches.
-                    matches = fscanf(file, " %d//%d", &vertexId[2], &normalId[2]);
-                    if (matches != 2 && matches != 0) {
-                        LOG(WARNING) << "Face matches, expected 2, read: " << matches;
-                        break;
-                    }
-                }
-
-                if (matches == 0) {
-                    break;
-                }
-
-                CopyFaceToCarVertex(currentVertices, currentTextures, currentNormals, vertexId[2],
-                                    textureId[2], normalId[2], &carVertices[2]);
-
-                carPartsMap->at(currentGroupName).vertices.push_back(carVertices[0]);
-                carPartsMap->at(currentGroupName).vertices.push_back(carVertices[1]);
-                carPartsMap->at(currentGroupName).vertices.push_back(carVertices[2]);
-
-                carVertices[1] = carVertices[2];
-            } while (true);
-
-        } else {
-            // LOG(WARNING) << "Unknown tag " << lineHeader << ". Skipped";
-            fgets(lineHeader, sizeof(lineHeader), file);
-            continue;
-        }
-    }
-
-    fclose(file);
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/ObjReader.h b/cpp/surround_view/service-impl/ObjReader.h
deleted file mode 100644
index c19be14..0000000
--- a/cpp/surround_view/service-impl/ObjReader.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
-#define SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
-
-#include <map>
-#include <string>
-
-#include "core_lib.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using android_auto::surround_view::CarPart;
-
-// ReadObjOptions for processing obj's vertex coordinates.
-// Sequence of processing ReadObjOptions:
-// 1. coordinate_mapping
-// 2. scales
-// 3. offsets
-struct ReadObjOptions {
-    // Maps obj coordinates to the output overlay coordinate.
-    // 0 <-> x, 1 <-> y, 2 <-> z
-    // Default is {0, 1, 2}, without coordinate changes.
-    int coordinateMapping[3] = {0, 1, 2};
-
-    // scale of each coordinate (after offsets).
-    float scales[3] = {1.0f, 1.0f, 1.0f};
-
-    // offset of each coordinate (after mapping).
-    float offsets[3] = {0, 0, 0};
-
-    // Optional mtl filename. String name is obj file is used if this is empty.
-    std::string mtlFilename;
-};
-
-// Reads obj file to vector of OverlayVertex.
-// |obj_filename| is the full path and name of the obj file.
-// |car_parts_map| is a map containing all car parts.
-// Now it only supports two face formats:
-// 1. f x/x/x x/x/x x/x/x ...
-// 2. f x//x x//x x//x ...
-// b/
-bool ReadObjFromFile(const std::string& objFilename, std::map<std::string, CarPart>* carPartsMap);
-
-// Reads obj file to vector of OverlayVertex.
-// |obj_filename| is the full path and name of the obj file.
-// |option| provides optional changes on the coordinates.
-// |car_parts_map| is a map containing all car parts.
-bool ReadObjFromFile(const std::string& obFilename, const ReadObjOptions& option,
-                     std::map<std::string, CarPart>* carPartsMap);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_OBJREADER_H_
diff --git a/cpp/surround_view/service-impl/ObjReaderTests.cpp b/cpp/surround_view/service-impl/ObjReaderTests.cpp
deleted file mode 100644
index 1c86737..0000000
--- a/cpp/surround_view/service-impl/ObjReaderTests.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "ObjReaderTests"
-
-#include "ObjReader.h"
-
-#include "MtlReader.h"
-#include "core_lib.h"
-
-#include <gtest/gtest.h>
-#include <map>
-#include <string>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-TEST(ObjParserTests, ReadObjFileSuccess) {
-    std::map<std::string, CarPart> carPartsMap;
-    EXPECT_TRUE(ReadObjFromFile("vendor/etc/automotive/sv/sample_car.obj", &carPartsMap));
-    EXPECT_NE(carPartsMap.size(), 0);
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundView2dSession.cpp b/cpp/surround_view/service-impl/SurroundView2dSession.cpp
deleted file mode 100644
index 2d837e0..0000000
--- a/cpp/surround_view/service-impl/SurroundView2dSession.cpp
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-
-#include "SurroundView2dSession.h"
-
-#include "CameraUtils.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware_buffer.h>
-#include <system/camera_metadata.h>
-#include <utils/SystemClock.h>
-#include <utils/Trace.h>
-#include <vndk/hardware_buffer.h>
-
-#include <thread>
-
-using ::std::adopt_lock;
-using ::std::lock;
-using ::std::lock_guard;
-using ::std::map;
-using ::std::mutex;
-using ::std::scoped_lock;
-using ::std::string;
-using ::std::thread;
-using ::std::unique_lock;
-using ::std::unique_ptr;
-using ::std::vector;
-
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::camera::device::V3_2::Stream;
-
-using GraphicsPixelFormat = ::android::hardware::graphics::common::V1_0::PixelFormat;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Macro for obtaining a uint64_t memory_id from the camera index and buffer_id.
-#define GET_MEMORY_ID(cam_index, buffer_id) ((static_cast<uint64_t>(cam_index) << 32) | buffer_id)
-
-// TODO(b/158479099): There are a lot of redundant code between 2d and 3d.
-// Decrease the degree of redundancy.
-typedef struct {
-    int32_t id;
-    int32_t width;
-    int32_t height;
-    int32_t format;
-    int32_t direction;
-    int32_t framerate;
-} RawStreamConfig;
-
-static const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
-static const int kInputNumChannels = 4;
-static const int kOutputNumChannels = 3;
-static const int kNumFrames = 4;
-static const int kSv2dViewId = 0;
-static const float kUndistortionScales[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
-SurroundView2dSession::FramesHandler::FramesHandler(
-    sp<IEvsCamera> pCamera, sp<SurroundView2dSession> pSession)
-    : mCamera(pCamera),
-      mSession(pSession) {}
-
-Return<void> SurroundView2dSession::FramesHandler::deliverFrame(
-    const BufferDesc_1_0& bufDesc_1_0) {
-    LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
-    mCamera->doneWithFrame(bufDesc_1_0);
-
-    return {};
-}
-
-Return<void> SurroundView2dSession::FramesHandler::deliverFrame_1_1(
-    const hidl_vec<BufferDesc_1_1>& buffers) {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
-    mSession->mSequenceId++;
-
-    {
-        scoped_lock<mutex> lock(mSession->mAccessLock);
-        if (mSession->mProcessingEvsFrames) {
-            LOG(WARNING) << "EVS frames are being processed. Skip frames:"
-                         << mSession->mSequenceId;
-            mCamera->doneWithFrame_1_1(buffers);
-            return {};
-        } else {
-            // Sets the flag to true immediately so the new coming frames will
-            // be skipped.
-            mSession->mProcessingEvsFrames = true;
-        }
-    }
-
-    if (buffers.size() != kNumFrames) {
-        scoped_lock<mutex> lock(mSession->mAccessLock);
-        LOG(ERROR) << "The number of incoming frames is " << buffers.size()
-                   << ", which is different from the number " << kNumFrames
-                   << ", specified in config file";
-        mSession->mProcessingEvsFrames = false;
-        mCamera->doneWithFrame_1_1(buffers);
-        return {};
-    }
-
-    {
-        scoped_lock<mutex> lock(mSession->mAccessLock);
-        vector<int> indices;
-        for (const auto& id
-                : mSession->mIOModuleConfig->cameraConfig.evsCameraIds) {
-            for (int i = 0; i < kNumFrames; i++) {
-                if (buffers[i].deviceId == id) {
-                    indices.emplace_back(i);
-                    break;
-                }
-            }
-        }
-
-        if (indices.size() != kNumFrames) {
-            LOG(ERROR) << "The frames are not from the cameras we expected!";
-            mSession->mProcessingEvsFrames = false;
-            mCamera->doneWithFrame_1_1(buffers);
-            return {};
-        }
-
-        if (mSession->mGpuAccelerationEnabled) {
-            for (int i = 0; i < kNumFrames; i++) {
-                LOG(DEBUG) << "Importing graphic buffer from camera ["
-                           << buffers[indices[i]].deviceId << "]";
-                const AHardwareBuffer_Desc* pDesc = reinterpret_cast<const AHardwareBuffer_Desc*>(
-                        &buffers[indices[i]].buffer.description);
-
-                AHardwareBuffer* hardwareBuffer;
-                status_t status = AHardwareBuffer_createFromHandle(
-                        pDesc, buffers[indices[i]].buffer.nativeHandle,
-                        AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer);
-
-                if (status != NO_ERROR) {
-                    LOG(ERROR) << "Can't create AHardwareBuffer from handle. Error: " << status;
-                    return {};
-                }
-
-                mSession->mInputPointers[i].gpu_data_pointer = static_cast<void*>(hardwareBuffer);
-                // Set memory_id to enable buffer caching.
-                // higher 32 bits are for camera index, lower 32 bits for bufferId.
-                mSession->mInputPointers[i].memory_id
-                        = GET_MEMORY_ID(indices[i], buffers[indices[i]].bufferId);
-
-                // Keep a reference to the EVS graphic buffers, so we can
-                // release them after Surround View stitching is done.
-                mSession->mEvsGraphicBuffers = buffers;
-            }
-        } else {
-            for (int i = 0; i < kNumFrames; i++) {
-                LOG(DEBUG) << "Copying buffer from camera [" << buffers[indices[i]].deviceId
-                           << "] to Surround View Service";
-                mSession->copyFromBufferToPointers(buffers[indices[i]],
-                                                   mSession->mInputPointers[i]);
-            }
-
-            // On the CPU version, we do not need to hold the Graphic Buffers
-            // any more since they are copied already.
-            mCamera->doneWithFrame_1_1(buffers);
-        }
-    }
-
-    // Notify the session that a new set of frames is ready
-    mSession->mFramesSignal.notify_all();
-
-    ATRACE_END();
-
-    return {};
-}
-
-Return<void> SurroundView2dSession::FramesHandler::notify(const EvsEventDesc& event) {
-    switch(event.aType) {
-        case EvsEventType::STREAM_STOPPED:
-            // The Surround View STREAM_STOPPED event is generated when the
-            // service finished processing the queued frames. So it does not
-            // rely on the Evs STREAM_STOPPED event.
-            LOG(INFO) << "Received a STREAM_STOPPED event from Evs.";
-            break;
-
-        case EvsEventType::PARAMETER_CHANGED:
-            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
-                      << " is set to " << event.payload[1];
-            break;
-
-        // Below events are ignored in reference implementation.
-        case EvsEventType::STREAM_STARTED:
-        [[fallthrough]];
-        case EvsEventType::FRAME_DROPPED:
-        [[fallthrough]];
-        case EvsEventType::TIMEOUT:
-            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
-                      << "is received but ignored.";
-            break;
-        default:
-            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
-            break;
-    }
-
-    return {};
-}
-
-bool SurroundView2dSession::copyFromBufferToPointers(
-    BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    AHardwareBuffer_Desc* pDesc =
-        reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
-
-    ATRACE_BEGIN("Create Graphic Buffer");
-    // create a GraphicBuffer from the existing handle
-    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
-        buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
-        pDesc->height, pDesc->format, pDesc->layers,
-        GRALLOC_USAGE_HW_TEXTURE, pDesc->stride);
-
-    if (inputBuffer == nullptr) {
-        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
-        // Returning "true" in this error condition because we already released the
-        // previous image (if any) and so the texture may change in unpredictable
-        // ways now!
-        return false;
-    } else {
-        LOG(INFO) << "Managed to allocate GraphicBuffer with "
-                  << " width: " << pDesc->width
-                  << " height: " << pDesc->height
-                  << " format: " << pDesc->format
-                  << " stride: " << pDesc->stride;
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("Lock input buffer (gpu to cpu)");
-    // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
-    // lock, return false.
-    void* inputDataPtr;
-    inputBuffer->lock(
-        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
-        &inputDataPtr);
-    if (!inputDataPtr) {
-        LOG(ERROR) << "Failed to gain read access to GraphicBuffer";
-        inputBuffer->unlock();
-        return false;
-    } else {
-        LOG(INFO) << "Managed to get read access to GraphicBuffer";
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("Copy input data");
-    // Both source and destination are with 4 channels
-    memcpy(pointers.cpu_data_pointer, inputDataPtr,
-           pDesc->height * pDesc->width * kInputNumChannels);
-    LOG(DEBUG) << "Buffer copying finished";
-    ATRACE_END();
-
-    ATRACE_BEGIN("Unlock input buffer (cpu to gpu)");
-    inputBuffer->unlock();
-    ATRACE_END();
-
-    // Paired with ATRACE_BEGIN in the beginning of the method.
-    ATRACE_END();
-
-    return true;
-}
-
-void SurroundView2dSession::processFrames() {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    while (true) {
-        {
-            unique_lock<mutex> lock(mAccessLock);
-
-            if (mStreamState != RUNNING) {
-                break;
-            }
-
-            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
-        }
-
-        handleFrames(mSequenceId);
-
-        {
-            // Set the boolean to false to receive the next set of frames.
-            scoped_lock<mutex> lock(mAccessLock);
-            mProcessingEvsFrames = false;
-        }
-    }
-
-    // Notify the SV client that no new results will be delivered.
-    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
-    mStream->notify(SvEvent::STREAM_STOPPED);
-
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-        mStreamState = STOPPED;
-        mStream = nullptr;
-        LOG(DEBUG) << "Stream marked STOPPED.";
-    }
-
-    ATRACE_END();
-}
-
-SurroundView2dSession::SurroundView2dSession(sp<IEvsEnumerator> pEvs,
-                                             IOModuleConfig* pConfig)
-    : mEvs(pEvs),
-      mIOModuleConfig(pConfig),
-      mStreamState(STOPPED) {}
-
-SurroundView2dSession::~SurroundView2dSession() {
-    // In case the client did not call stopStream properly, we should stop the
-    // stream explicitly. Otherwise the process thread will take forever to
-    // join.
-    stopStream();
-
-    // Waiting for the process thread to finish the buffered frames.
-    if (mProcessThread.joinable()) {
-        mProcessThread.join();
-    }
-
-    mEvs->closeCamera(mCamera);
-
-    // TODO(b/175176576): properly release the mInputPointers and mOutputPointer
-}
-
-// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
-Return<SvResult> SurroundView2dSession::startStream(
-    const sp<ISurroundViewStream>& stream) {
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock<mutex> lock(mAccessLock);
-
-    if (!mIsInitialized && !initialize()) {
-        LOG(ERROR) << "There is an error while initializing the use case. "
-                   << "Exiting";
-        return SvResult::INTERNAL_ERROR;
-    }
-
-    if (mStreamState != STOPPED) {
-        LOG(ERROR) << "Ignoring startVideoStream call"
-                   << "when a stream is already running.";
-        return SvResult::INTERNAL_ERROR;
-    }
-
-    if (stream == nullptr) {
-        LOG(ERROR) << "The input stream is invalid";
-        return SvResult::INTERNAL_ERROR;
-    }
-    mStream = stream;
-
-    mSequenceId = 0;
-    startEvs();
-
-    // TODO(b/158131080): the STREAM_STARTED event is not implemented in EVS
-    // reference implementation yet. Once implemented, this logic should be
-    // moved to EVS notify callback.
-    LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
-    mStream->notify(SvEvent::STREAM_STARTED);
-    mProcessingEvsFrames = false;
-
-    // Start the frame generation thread
-    mStreamState = RUNNING;
-
-    mProcessThread = thread([this]() {
-        processFrames();
-    });
-
-    return SvResult::OK;
-}
-
-Return<void> SurroundView2dSession::stopStream() {
-    LOG(DEBUG) << __FUNCTION__;
-    unique_lock<mutex> lock(mAccessLock);
-
-    if (mStreamState == RUNNING) {
-        // Tell the processFrames loop to stop processing frames
-        mStreamState = STOPPING;
-
-        // Stop the EVS stream asynchronizely
-        mCamera->stopVideoStream();
-        mFramesHandler = nullptr;
-    }
-
-    return {};
-}
-
-Return<void> SurroundView2dSession::doneWithFrames(
-    const SvFramesDesc& svFramesDesc){
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock <mutex> lock(mAccessLock);
-
-    mFramesRecord.inUse = false;
-
-    (void)svFramesDesc;
-    return {};
-}
-
-// Methods from ISurroundView2dSession follow.
-Return<void> SurroundView2dSession::get2dMappingInfo(
-    get2dMappingInfo_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-
-    _hidl_cb(mInfo);
-    return {};
-}
-
-Return<SvResult> SurroundView2dSession::set2dConfig(
-    const Sv2dConfig& sv2dConfig) {
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock <mutex> lock(mAccessLock);
-
-    if (sv2dConfig.width <=0 || sv2dConfig.width > 4096) {
-        LOG(WARNING) << "The width of 2d config is out of the range (0, 4096]"
-                     << "Ignored!";
-        return SvResult::INVALID_ARG;
-    }
-
-    mConfig.width = sv2dConfig.width;
-    mConfig.blending = sv2dConfig.blending;
-    mHeight = mConfig.width * mInfo.height / mInfo.width;
-
-    if (mStream != nullptr) {
-        LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
-        mStream->notify(SvEvent::CONFIG_UPDATED);
-    }
-
-    return SvResult::OK;
-}
-
-Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-
-    _hidl_cb(mConfig);
-    return {};
-}
-
-Return<void> SurroundView2dSession::projectCameraPoints(const hidl_vec<Point2dInt>& points2dCamera,
-                                                        const hidl_string& cameraId,
-                                                        projectCameraPoints_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::vector<Point2dFloat> outPoints;
-    bool cameraIdFound = false;
-    int cameraIndex = 0;
-    // Note: mEvsCameraIds must be in the order front, right, rear, left.
-    for (auto& evsCameraId : mEvsCameraIds) {
-        if (cameraId == evsCameraId) {
-            cameraIdFound = true;
-            LOG(DEBUG) << "Camera id found for projection: " << cameraId;
-            break;
-        }
-        cameraIndex++;
-    }
-
-    if (!cameraIdFound) {
-        LOG(ERROR) << "Camera id not found for projection: " << cameraId;
-        _hidl_cb(outPoints);
-        return {};
-    }
-
-    int width = mConfig.width;
-    int height = mHeight;
-    for (const auto& cameraPoint : points2dCamera) {
-        Point2dFloat outPoint = {false, 0.0, 0.0};
-        // Check of the camear point is within the camera resolution bounds.
-        if (cameraPoint.x < 0 || cameraPoint.x > width - 1 || cameraPoint.y < 0 ||
-            cameraPoint.y > height - 1) {
-            LOG(WARNING) << "Camera point (" << cameraPoint.x << ", " << cameraPoint.y
-                         << ") is out of camera resolution bounds.";
-            outPoint.isValid = false;
-            outPoints.push_back(outPoint);
-            continue;
-        }
-
-        // Project points using mSurroundView function.
-        const Coordinate2dInteger camPoint(cameraPoint.x, cameraPoint.y);
-        Coordinate2dFloat projPoint2d(0.0, 0.0);
-
-        outPoint.isValid =
-                mSurroundView->GetProjectionPointFromRawCameraToSurroundView2d(camPoint,
-                                                                               cameraIndex,
-                                                                               &projPoint2d);
-        outPoint.x = projPoint2d.x;
-        outPoint.y = projPoint2d.y;
-        outPoints.push_back(outPoint);
-    }
-
-    _hidl_cb(outPoints);
-    return {};
-}
-
-// TODO(b/175176765): implement a GPU version of this method separately.
-bool SurroundView2dSession::handleFrames(int sequenceId) {
-    LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
-
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    // TODO(b/157498592): Now only one sets of EVS input frames and one SV
-    // output frame is supported. Implement buffer queue for both of them.
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-
-        if (mFramesRecord.inUse) {
-            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
-            mStream->notify(SvEvent::FRAME_DROPPED);
-
-            // For GPU solution only (the frames were released already for CPU solution).
-            if (mGpuAccelerationEnabled) {
-                mCamera->doneWithFrame_1_1(mEvsGraphicBuffers);
-            }
-            return true;
-        }
-    }
-
-    // TODO(b/175177030): modifying the width/length on the fly is not supported by the GPU approach
-    // yet.
-    if (!mGpuAccelerationEnabled) {
-        if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
-            LOG(DEBUG) << "Config changed. Re-allocate memory."
-                       << " Old width: " << mOutputWidth << " Old height: " << mOutputHeight
-                       << " New width: " << mConfig.width << " New height: " << mHeight;
-            delete[] static_cast<char*>(mOutputPointer.cpu_data_pointer);
-            mOutputWidth = mConfig.width;
-            mOutputHeight = mHeight;
-            mOutputPointer.height = mOutputHeight;
-            mOutputPointer.width = mOutputWidth;
-            mOutputPointer.format = Format::RGB;
-            mOutputPointer.cpu_data_pointer =
-                    static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
-
-            if (!mOutputPointer.cpu_data_pointer) {
-                LOG(ERROR) << "Memory allocation failed. Exiting.";
-                return false;
-            }
-
-            Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
-            mSurroundView->Update2dOutputResolution(size);
-
-            mSvTexture = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGB_888, 1,
-                                           GRALLOC_USAGE_HW_TEXTURE, "SvTexture");
-            if (mSvTexture->initCheck() == OK) {
-                LOG(INFO) << "Successfully allocated Graphic Buffer";
-            } else {
-                LOG(ERROR) << "Failed to allocate Graphic Buffer";
-                return false;
-            }
-        }
-        LOG(INFO) << "Output Pointer data format: " << mOutputPointer.format;
-    }
-
-    ATRACE_BEGIN("SV core lib method: Get2dSurroundView");
-    const string gpuEnabledText = mGpuAccelerationEnabled ? " with GPU acceleration flag enabled"
-                                                          : " with GPU acceleration flag disabled";
-    if (mSurroundView->Get2dSurroundView(mInputPointers, &mOutputPointer)) {
-        LOG(INFO) << "Get2dSurroundView succeeded" << gpuEnabledText;
-    } else {
-        LOG(ERROR) << "Get2dSurroundView failed" << gpuEnabledText;
-    }
-    ATRACE_END();
-
-    // For GPU solution only (the frames were released already for CPU solution).
-    if (mGpuAccelerationEnabled) {
-        ATRACE_BEGIN("Release the evs frames");
-        mCamera->doneWithFrame_1_1(mEvsGraphicBuffers);
-        ATRACE_END();
-    }
-
-    ANativeWindowBuffer* buffer;
-    if (mGpuAccelerationEnabled) {
-        buffer = mOutputHolder->getNativeBuffer();
-    } else {
-        ATRACE_BEGIN("Lock output texture (gpu to cpu)");
-        void* textureDataPtr = nullptr;
-        mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
-                         &textureDataPtr);
-        ATRACE_END();
-
-        if (!textureDataPtr) {
-            LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
-            return false;
-        }
-
-        ATRACE_BEGIN("Copy output result");
-        // Note: there is a chance that the stride of the texture is not the same
-        // as the width. For example, when the input frame is 1920 * 1080, the
-        // width is 1080, but the stride is 2048. So we'd better copy the data line
-        // by line, instead of single memcpy.
-        uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
-        uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.cpu_data_pointer);
-        const int readStride = mOutputWidth * kOutputNumChannels;
-        const int writeStride = mSvTexture->getStride() * kOutputNumChannels;
-        if (readStride == writeStride) {
-            memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
-        } else {
-            for (int i = 0; i < mSvTexture->getHeight(); i++) {
-                memcpy(writePtr, readPtr, readStride);
-                writePtr = writePtr + writeStride;
-                readPtr = readPtr + readStride;
-            }
-        }
-        LOG(DEBUG) << "memcpy finished";
-        ATRACE_END();
-
-        ATRACE_BEGIN("Unlock output texture (cpu to gpu)");
-        mSvTexture->unlock();
-        ATRACE_END();
-
-        buffer = mSvTexture->getNativeBuffer();
-        LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
-    }
-
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-
-        mFramesRecord.frames.svBuffers.resize(1);
-        SvBuffer& svBuffer = mFramesRecord.frames.svBuffers[0];
-        svBuffer.viewId = kSv2dViewId;
-        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
-        AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<AHardwareBuffer_Desc*>(
-                &svBuffer.hardwareBuffer.description);
-        if (mGpuAccelerationEnabled) {
-            pDesc->width = mOutputPointer.width;
-            pDesc->height = mOutputPointer.height;
-            pDesc->stride = mOutputHolder->getStride();
-            pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
-        } else {
-            pDesc->width = mOutputWidth;
-            pDesc->height = mOutputHeight;
-            pDesc->stride = mSvTexture->getStride();
-            pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
-        }
-        pDesc->layers = 1;
-        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
-        mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
-        mFramesRecord.frames.sequenceId = sequenceId;
-
-        mFramesRecord.inUse = true;
-        mStream->receiveFrames(mFramesRecord.frames);
-    }
-
-    ATRACE_END();
-
-    return true;
-}
-
-// TODO(b/175176765): consider to HW-specific initialization procedures into
-// separate methods.
-bool SurroundView2dSession::initialize() {
-    lock_guard<mutex> lock(mAccessLock, adopt_lock);
-
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    if (!setupEvs()) {
-        LOG(ERROR) << "Failed to setup EVS components for 2d session";
-        return false;
-    }
-
-    // TODO(b/150412555): ask core-lib team to add API description for "create"
-    // method in the .h file.
-    // The create method will never return a null pointer based the API
-    // description.
-    mSurroundView = unique_ptr<SurroundView>(Create());
-
-    SurroundViewStaticDataParams params =
-            SurroundViewStaticDataParams(mCameraParams,
-                                         mIOModuleConfig->sv2dConfig.sv2dParams,
-                                         mIOModuleConfig->sv3dConfig.sv3dParams,
-                                         vector<float>(std::begin(kUndistortionScales),
-                                                       std::end(kUndistortionScales)),
-                                         mIOModuleConfig->sv2dConfig.carBoundingBox,
-                                         mIOModuleConfig->carModelConfig.carModel.texturesMap,
-                                         mIOModuleConfig->carModelConfig.carModel.partsMap);
-    mGpuAccelerationEnabled = mIOModuleConfig->sv2dConfig.sv2dParams.gpu_acceleration_enabled;
-
-    ATRACE_BEGIN("SV core lib method: SetStaticData");
-    mSurroundView->SetStaticData(params);
-    ATRACE_END();
-
-    ATRACE_BEGIN("SV core lib method: Start2dPipeline");
-    const string gpuEnabledText = mGpuAccelerationEnabled ? "with GPU acceleration flag enabled"
-                                                          : "with GPU acceleration flag disabled";
-    if (mSurroundView->Start2dPipeline()) {
-        LOG(INFO) << "Start2dPipeline succeeded " << gpuEnabledText;
-    } else {
-        LOG(ERROR) << "Start2dPipeline failed " << gpuEnabledText;
-        return false;
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("Allocate cpu buffers");
-    mInputPointers.resize(kNumFrames);
-    for (int i = 0; i < kNumFrames; i++) {
-        mInputPointers[i].width = mCameraParams[i].size.width;
-        mInputPointers[i].height = mCameraParams[i].size.height;
-
-        // Only allocate CPU memory for CPU solution
-        // For GPU solutions, the Graphic Buffers from EVS will be converted and
-        // stored in gpu_data_pointer
-        if (!mGpuAccelerationEnabled) {
-            mInputPointers[i].format = Format::RGBA;
-            mInputPointers[i].cpu_data_pointer =
-                    static_cast<void*>(new char[mInputPointers[i].width * mInputPointers[i].height *
-                                                kInputNumChannels]);
-        }
-    }
-    LOG(INFO) << "Allocated " << kNumFrames << " input pointers";
-
-    mOutputWidth = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.width;
-    mOutputHeight = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.height;
-
-    mConfig.width = mOutputWidth;
-    mConfig.blending = SvQuality::HIGH;
-    mHeight = mOutputHeight;
-
-    mOutputPointer.height = mOutputHeight;
-    mOutputPointer.width = mOutputWidth;
-
-    // Only allocate CPU memory for CPU solution
-    if (!mGpuAccelerationEnabled) {
-        mOutputPointer.format = Format::RGB;
-        mOutputPointer.cpu_data_pointer =
-                static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
-
-        if (!mOutputPointer.cpu_data_pointer) {
-            LOG(ERROR) << "Memory allocation failed. Exiting.";
-            return false;
-        }
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("Allocate output texture");
-    if (mGpuAccelerationEnabled) {
-        mOutputHolder = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGBA_8888,
-                                          1, GRALLOC_USAGE_HW_TEXTURE, "SvOutputHolder");
-        if (mOutputHolder->initCheck() == OK) {
-            LOG(INFO) << "Successfully allocated Graphic Buffer for SvOutputHolder";
-        } else {
-            LOG(ERROR) << "Failed to allocate Graphic Buffer for SvOutputHolder";
-            return false;
-        }
-        mOutputPointer.gpu_data_pointer = static_cast<void*>(mOutputHolder->toAHardwareBuffer());
-        // Set output memory id one time to a one time unique value.
-        // 0 to (kNumFrames - 1) are used for inputs, using kNumFrames as higher 32 bits.
-        mOutputPointer.memory_id = GET_MEMORY_ID(kNumFrames, 0x00);
-    } else {
-        mSvTexture = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGB_888, 1,
-                                       GRALLOC_USAGE_HW_TEXTURE, "SvTexture");
-        if (mSvTexture->initCheck() == OK) {
-            LOG(INFO) << "Successfully allocated Graphic Buffer";
-        } else {
-            LOG(ERROR) << "Failed to allocate Graphic Buffer";
-            return false;
-        }
-    }
-
-    // Note: sv2dParams is in meters while mInfo must be in milli-meters.
-    mInfo.width = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.width * 1000.0;
-    mInfo.height = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.height * 1000.0;
-    mInfo.center.isValid = true;
-    mInfo.center.x = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.x * 1000.0;
-    mInfo.center.y = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.y * 1000.0;
-
-    mIsInitialized = true;
-
-    ATRACE_END();
-
-    return true;
-}
-
-bool SurroundView2dSession::setupEvs() {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    // Reads the camera related information from the config object
-    const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
-
-    // Setup for EVS
-    LOG(INFO) << "Requesting camera list";
-    mEvs->getCameraList_1_1(
-            [this, evsGroupId] (hidl_vec<CameraDesc> cameraList) {
-        LOG(INFO) << "Camera list callback received " << cameraList.size();
-        for (auto&& cam : cameraList) {
-            LOG(INFO) << "Found camera " << cam.v1.cameraId;
-            if (cam.v1.cameraId == evsGroupId) {
-                mCameraDesc = cam;
-            }
-        }
-    });
-
-    bool foundCfg = false;
-    std::unique_ptr<Stream> targetCfg(new Stream());
-
-    // This logic picks the configuration with the largest area that supports
-    // RGBA8888 format
-    int32_t maxArea = 0;
-    camera_metadata_entry_t streamCfgs;
-    if (!find_camera_metadata_entry(
-             reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
-             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-             &streamCfgs)) {
-        // Stream configurations are found in metadata
-        RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(
-            streamCfgs.data.i32);
-        for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
-            if (ptr->direction ==
-                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
-                ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
-
-                if (ptr->width * ptr->height > maxArea) {
-                    targetCfg->id = ptr->id;
-                    targetCfg->width = ptr->width;
-                    targetCfg->height = ptr->height;
-
-                    // This client always wants below input data format
-                    targetCfg->format =
-                        static_cast<GraphicsPixelFormat>(
-                            HAL_PIXEL_FORMAT_RGBA_8888);
-
-                    maxArea = ptr->width * ptr->height;
-
-                    foundCfg = true;
-                }
-            }
-            ++ptr;
-        }
-    } else {
-        LOG(WARNING) << "No stream configuration data is found; "
-                     << "default parameters will be used.";
-    }
-
-    if (!foundCfg) {
-        LOG(INFO) << "No config was found";
-        targetCfg = nullptr;
-        return false;
-    }
-
-    string camId = mCameraDesc.v1.cameraId.c_str();
-    mCamera = mEvs->openCamera_1_1(camId.c_str(), *targetCfg);
-    if (mCamera == nullptr) {
-        LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
-        return false;
-    } else {
-        LOG(INFO) << "Logical camera " << camId << " is opened successfully";
-    }
-
-    mEvsCameraIds = mIOModuleConfig->cameraConfig.evsCameraIds;
-    if (mEvsCameraIds.size() < kNumFrames) {
-        LOG(ERROR) << "Incorrect camera info is stored in the camera config";
-        return false;
-    }
-
-    map<string, AndroidCameraParams> cameraIdToAndroidParameters;
-    for (const auto& id : mEvsCameraIds) {
-        AndroidCameraParams params;
-        if (getAndroidCameraParams(mCamera, id, params)) {
-            cameraIdToAndroidParameters.emplace(id, params);
-            LOG(INFO) << "Camera parameters are fetched successfully for "
-                      << "physical camera: " << id;
-        } else {
-            LOG(ERROR) << "Failed to get camera parameters for "
-                       << "physical camera: " << id;
-            return false;
-        }
-    }
-
-    mCameraParams =
-            convertToSurroundViewCameraParams(cameraIdToAndroidParameters);
-
-    for (auto& camera : mCameraParams) {
-        camera.size.width = targetCfg->width;
-        camera.size.height = targetCfg->height;
-        camera.circular_fov = 179;
-    }
-
-    // Add validity mask filenames.
-    for (int i = 0; i < mCameraParams.size(); i++) {
-        mCameraParams[i].validity_mask_filename = mIOModuleConfig->cameraConfig.maskFilenames[i];
-    }
-    ATRACE_END();
-    return true;
-}
-
-bool SurroundView2dSession::startEvs() {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    mFramesHandler = new FramesHandler(mCamera, this);
-    Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
-    if (result != EvsResult::OK) {
-        LOG(ERROR) << "Failed to start video stream";
-        return false;
-    } else {
-        LOG(INFO) << "Video stream was started successfully";
-    }
-
-    ATRACE_END();
-
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundView2dSession.h b/cpp/surround_view/service-impl/SurroundView2dSession.h
deleted file mode 100644
index e7a9e17..0000000
--- a/cpp/surround_view/service-impl/SurroundView2dSession.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include "IOModule.h"
-
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/sv/1.0/types.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
-
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <thread>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using namespace ::android::hardware::automotive::sv::V1_0;
-using namespace ::android_auto::surround_view;
-
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
-using ::android::sp;
-using ::std::condition_variable;
-
-using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-class SurroundView2dSession : public ISurroundView2dSession {
-
-    /*
-     * FramesHandler:
-     * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
-     * hold onto the most recent image buffer, returning older ones.
-     * Note that the video frames are delivered on a background thread, while the control interface
-     * is actuated from the applications foreground thread.
-     */
-    class FramesHandler : public IEvsCameraStream {
-    public:
-        FramesHandler(sp<IEvsCamera> pCamera, sp<SurroundView2dSession> pSession);
-
-    private:
-        // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
-        Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
-
-        // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
-        Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
-        Return<void> notify(const EvsEventDesc& event) override;
-
-        // Values initialized as startup
-        sp <IEvsCamera> mCamera;
-
-        sp<SurroundView2dSession> mSession;
-    };
-
-public:
-    SurroundView2dSession(sp<IEvsEnumerator> pEvs, IOModuleConfig* pConfig);
-    ~SurroundView2dSession();
-    bool initialize();
-
-    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
-    Return<SvResult> startStream(
-        const sp<ISurroundViewStream>& stream) override;
-    Return<void> stopStream() override;
-    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
-
-    // Methods from ISurroundView2dSession follow.
-    Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
-    Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
-    Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
-    Return<void> projectCameraPoints(
-        const hidl_vec<Point2dInt>& points2dCamera,
-        const hidl_string& cameraId,
-        projectCameraPoints_cb _hidl_cb) override;
-
-private:
-    void processFrames();
-
-    // Set up and open the Evs camera(s), triggered when session is created.
-    bool setupEvs();
-
-    // Start Evs camera video stream, triggered when SV stream is started.
-    bool startEvs();
-
-    bool handleFrames(int sequenceId);
-
-    bool copyFromBufferToPointers(BufferDesc_1_1 buffer,
-                                  SurroundViewInputBufferPointers pointers);
-
-    enum StreamStateValues {
-        STOPPED,
-        RUNNING,
-        STOPPING,
-        DEAD,
-    };
-
-    // EVS Enumerator to control the start/stop of the Evs Stream
-    sp<IEvsEnumerator> mEvs;
-
-    IOModuleConfig* mIOModuleConfig;
-
-    // Instance and metadata for the opened Evs Camera
-    sp<IEvsCamera> mCamera;
-    CameraDesc mCameraDesc;
-    std::vector<SurroundViewCameraParams> mCameraParams;
-
-    // Stream subscribed for the session.
-    sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
-    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
-
-    std::thread mProcessThread; // The thread we'll use to process frames
-
-    // Reference to the inner class, to handle the incoming Evs frames
-    sp<FramesHandler> mFramesHandler;
-
-    // Used to signal a set of frames is ready
-    condition_variable mFramesSignal GUARDED_BY(mAccessLock);
-    bool mProcessingEvsFrames GUARDED_BY(mAccessLock);
-
-    int mSequenceId;
-
-    struct FramesRecord {
-        SvFramesDesc frames;
-        bool inUse = false;
-    };
-
-    FramesRecord mFramesRecord GUARDED_BY(mAccessLock);
-
-    // Synchronization necessary to deconflict mCaptureThread from the main
-    // service thread
-    std::mutex mAccessLock;
-
-    std::vector<std::string> mEvsCameraIds GUARDED_BY(mAccessLock);
-
-    std::unique_ptr<SurroundView> mSurroundView GUARDED_BY(mAccessLock);
-
-    std::vector<SurroundViewInputBufferPointers>
-        mInputPointers GUARDED_BY(mAccessLock);
-    SurroundViewResultPointer mOutputPointer GUARDED_BY(mAccessLock);
-
-    Sv2dConfig mConfig GUARDED_BY(mAccessLock);
-    int mHeight GUARDED_BY(mAccessLock);
-
-    // TODO(b/158479099): Rename it to mMappingInfo
-    Sv2dMappingInfo mInfo GUARDED_BY(mAccessLock);
-    int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
-    sp<GraphicBuffer> mOutputHolder;
-
-    sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
-
-    bool mIsInitialized GUARDED_BY(mAccessLock) = false;
-
-    bool mGpuAccelerationEnabled;
-    hidl_vec<BufferDesc_1_1> mEvsGraphicBuffers;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
diff --git a/cpp/surround_view/service-impl/SurroundView2dSessionTests.cpp b/cpp/surround_view/service-impl/SurroundView2dSessionTests.cpp
deleted file mode 100644
index a452ddf..0000000
--- a/cpp/surround_view/service-impl/SurroundView2dSessionTests.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "SurroundView2dSessionTests"
-
-#include "mock-evs/MockEvsEnumerator.h"
-#include "mock-evs/MockSurroundViewCallback.h"
-
-#include "IOModule.h"
-#include "SurroundView2dSession.h"
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-
-#include <android-base/logging.h>
-
-#include <gtest/gtest.h>
-#include <time.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
-
-using android::hardware::automotive::sv::V1_0::Sv2dMappingInfo;
-using android::hardware::automotive::sv::V1_0::SvQuality;
-
-// Sv 2D output height and width set by the config file.
-const int kSv2dWidth = 768;
-const int kSv2dHeight = 1024;
-
-class SurroundView2dSessionTests : public ::testing::Test {
-protected:
-    void SetUp() override {
-        sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
-        mIoModule = new IOModule(kSvConfigFilename);
-        EXPECT_EQ(mIoModule->initialize(), IOStatus::OK);
-
-        mIoModule->getConfig(&mIoModuleConfig);
-
-        mSv2dSession = new SurroundView2dSession(fakeEvs, &mIoModuleConfig);
-        EXPECT_TRUE(mSv2dSession->initialize());
-    }
-
-    IOModule* mIoModule;
-    IOModuleConfig mIoModuleConfig;
-    sp<SurroundView2dSession> mSv2dSession;
-};
-
-TEST_F(SurroundView2dSessionTests, startAndStopSurroundView2dSession) {
-    sp<MockSurroundViewCallback> sv2dCallback =
-            new MockSurroundViewCallback(mSv2dSession);
-
-    EXPECT_EQ(mSv2dSession->startStream(sv2dCallback), SvResult::OK);
-
-    sleep(5);
-
-    mSv2dSession->stopStream();
-}
-
-TEST_F(SurroundView2dSessionTests, get2dMappingInfoSuccess) {
-    Sv2dMappingInfo sv2dMappingInfo;
-    mSv2dSession->get2dMappingInfo(
-        [&sv2dMappingInfo](const Sv2dMappingInfo& mappingInfo) {
-            sv2dMappingInfo = mappingInfo;
-        });
-
-    EXPECT_NE(sv2dMappingInfo.width, 0);
-    EXPECT_NE(sv2dMappingInfo.height, 0);
-    EXPECT_EQ(sv2dMappingInfo.center.x, 0.0f);
-    EXPECT_EQ(sv2dMappingInfo.center.y, 0.0f);
-}
-
-TEST_F(SurroundView2dSessionTests, get2dConfigSuccess) {
-    Sv2dConfig sv2dConfig;
-    mSv2dSession->get2dConfig(
-        [&sv2dConfig](const Sv2dConfig& config) {
-            sv2dConfig = config;
-        });
-
-    EXPECT_EQ(sv2dConfig.width, kSv2dWidth);
-    EXPECT_EQ(sv2dConfig.blending, SvQuality::HIGH);
-}
-
-// Sets a different config and checks of the received config matches.
-TEST_F(SurroundView2dSessionTests, setAndGet2dConfigSuccess) {
-    // Set config.
-    Sv2dConfig sv2dConfigSet = {kSv2dWidth / 2, SvQuality::LOW};
-    EXPECT_EQ(mSv2dSession->set2dConfig(sv2dConfigSet), SvResult::OK);
-
-    // Get config.
-    Sv2dConfig sv2dConfigReceived;
-    mSv2dSession->get2dConfig(
-        [&sv2dConfigReceived](const Sv2dConfig& config) {
-            sv2dConfigReceived = config;
-        });
-
-    EXPECT_EQ(sv2dConfigReceived.width, sv2dConfigSet.width);
-    EXPECT_EQ(sv2dConfigReceived.blending, sv2dConfigSet.blending);
-}
-
-// Projects center of each cameras and checks if valid projected point is received.
-TEST_F(SurroundView2dSessionTests, projectPoints2dSuccess) {
-    hidl_vec<Point2dInt> points2dCamera = {
-        /*Center point*/{.x = kSv2dWidth / 2, .y = kSv2dHeight /2}
-    };
-
-    std::vector<hidl_string> cameraIds = {"/dev/video60", "/dev/video61", "/dev/video62" ,
-            "/dev/video63"};
-
-    for (int i = 0; i < cameraIds.size(); i++) {
-        mSv2dSession->projectCameraPoints(points2dCamera, cameraIds[i],
-            [](const hidl_vec<Point2dFloat>& projectedPoints) {
-                EXPECT_TRUE(projectedPoints[0].isValid);
-            });
-    }
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundView3dSession.cpp b/cpp/surround_view/service-impl/SurroundView3dSession.cpp
deleted file mode 100644
index 7bb6f6d..0000000
--- a/cpp/surround_view/service-impl/SurroundView3dSession.cpp
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-
-#include "SurroundView3dSession.h"
-
-#include "CameraUtils.h"
-#include "sv_3d_params.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware_buffer.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-#include <system/camera_metadata.h>
-#include <utils/SystemClock.h>
-#include <utils/Trace.h>
-#include <vndk/hardware_buffer.h>
-
-#include <array>
-#include <set>
-#include <thread>
-
-using ::std::adopt_lock;
-using ::std::array;
-using ::std::lock;
-using ::std::lock_guard;
-using ::std::map;
-using ::std::mutex;
-using ::std::scoped_lock;
-using ::std::set;
-using ::std::string;
-using ::std::thread;
-using ::std::unique_lock;
-using ::std::unique_ptr;
-using ::std::vector;
-
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::camera::device::V3_2::Stream;
-using ::android::hardware::hidl_memory;
-using ::android::hidl::memory::V1_0::IMemory;
-
-using GraphicsPixelFormat = ::android::hardware::graphics::common::V1_0::PixelFormat;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-typedef struct {
-    int32_t id;
-    int32_t width;
-    int32_t height;
-    int32_t format;
-    int32_t direction;
-    int32_t framerate;
-} RawStreamConfig;
-
-static const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
-static const uint8_t kGrayColor = 128;
-static const int kNumFrames = 4;
-static const int kOutputNumChannels = 4;
-static const float kUndistortionScales[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
-SurroundView3dSession::FramesHandler::FramesHandler(
-    sp<IEvsCamera> pCamera, sp<SurroundView3dSession> pSession)
-    : mCamera(pCamera),
-      mSession(pSession) {}
-
-Return<void> SurroundView3dSession::FramesHandler::deliverFrame(
-    const BufferDesc_1_0& bufDesc_1_0) {
-    LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
-    mCamera->doneWithFrame(bufDesc_1_0);
-
-    return {};
-}
-
-Return<void> SurroundView3dSession::FramesHandler::deliverFrame_1_1(
-    const hidl_vec<BufferDesc_1_1>& buffers) {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
-    mSession->mSequenceId++;
-
-    {
-        scoped_lock<mutex> lock(mSession->mAccessLock);
-        if (mSession->mProcessingEvsFrames) {
-            LOG(WARNING) << "EVS frames are being processed. Skip frames:"
-                         << mSession->mSequenceId;
-            mCamera->doneWithFrame_1_1(buffers);
-            return {};
-        } else {
-            // Sets the flag to true immediately so the new coming frames will
-            // be skipped.
-            mSession->mProcessingEvsFrames = true;
-        }
-    }
-
-    if (buffers.size() != kNumFrames) {
-        scoped_lock<mutex> lock(mSession->mAccessLock);
-        LOG(ERROR) << "The number of incoming frames is " << buffers.size()
-                   << ", which is different from the number " << kNumFrames
-                   << ", specified in config file";
-        mSession->mProcessingEvsFrames = false;
-        mCamera->doneWithFrame_1_1(buffers);
-        return {};
-    }
-
-    {
-        scoped_lock<mutex> lock(mSession->mAccessLock);
-
-        // The incoming frames may not follow the same order as listed cameras.
-        // We should re-order them following the camera ids listed in camera
-        // config.
-        vector<int> indices;
-        for (const auto& id
-                : mSession->mIOModuleConfig->cameraConfig.evsCameraIds) {
-            for (int i = 0; i < kNumFrames; i++) {
-                if (buffers[i].deviceId == id) {
-                    indices.emplace_back(i);
-                    break;
-                }
-            }
-        }
-
-        // If the size of indices is smaller than the kNumFrames, it means that
-        // there is frame(s) that comes from different camera(s) than we
-        // expected.
-        if (indices.size() != kNumFrames) {
-            LOG(ERROR) << "The frames are not from the cameras we expected!";
-            mSession->mProcessingEvsFrames = false;
-            mCamera->doneWithFrame_1_1(buffers);
-            return {};
-        }
-
-        for (int i = 0; i < kNumFrames; i++) {
-            LOG(DEBUG) << "Importing graphic buffer from camera [" << buffers[indices[i]].deviceId
-                       << "]";
-            const AHardwareBuffer_Desc* pDesc = reinterpret_cast<const AHardwareBuffer_Desc*>(
-                    &buffers[indices[i]].buffer.description);
-
-            AHardwareBuffer* hardwareBuffer;
-            status_t status = AHardwareBuffer_createFromHandle(
-                    pDesc, buffers[indices[i]].buffer.nativeHandle,
-                    AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer);
-
-            if (status != NO_ERROR) {
-                LOG(ERROR) << "Can't create AHardwareBuffer from handle. Error: " << status;
-                return {};
-            }
-
-            mSession->mInputPointers[i].gpu_data_pointer = static_cast<void*>(hardwareBuffer);
-
-            // Keep a reference to the EVS graphic buffers, so we can
-            // release them after Surround View stitching is done.
-            mSession->mEvsGraphicBuffers = buffers;
-        }
-    }
-
-    // Notify the session that a new set of frames is ready
-    mSession->mFramesSignal.notify_all();
-
-    ATRACE_END();
-
-    return {};
-}
-
-Return<void> SurroundView3dSession::FramesHandler::notify(const EvsEventDesc& event) {
-    switch(event.aType) {
-        case EvsEventType::STREAM_STOPPED:
-            // The Surround View STREAM_STOPPED event is generated when the
-            // service finished processing the queued frames. So it does not
-            // rely on the Evs STREAM_STOPPED event.
-            LOG(INFO) << "Received a STREAM_STOPPED event from Evs.";
-            break;
-
-        case EvsEventType::PARAMETER_CHANGED:
-            LOG(INFO) << "Camera parameter " << std::hex << event.payload[0]
-                      << " is set to " << event.payload[1];
-            break;
-
-        // Below events are ignored in reference implementation.
-        case EvsEventType::STREAM_STARTED:
-        [[fallthrough]];
-        case EvsEventType::FRAME_DROPPED:
-        [[fallthrough]];
-        case EvsEventType::TIMEOUT:
-            LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
-                      << "is received but ignored.";
-            break;
-        default:
-            LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
-            break;
-    }
-
-    return {};
-}
-
-void SurroundView3dSession::processFrames() {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    ATRACE_BEGIN("SV core lib method: Start3dPipeline");
-    if (mSurroundView->Start3dPipeline()) {
-        LOG(INFO) << "Start3dPipeline succeeded";
-    } else {
-        LOG(ERROR) << "Start3dPipeline failed";
-        return;
-    }
-    ATRACE_END();
-
-    while (true) {
-        {
-            unique_lock<mutex> lock(mAccessLock);
-
-            if (mStreamState != RUNNING) {
-                break;
-            }
-
-            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
-        }
-
-        handleFrames(mSequenceId);
-
-        {
-            // Set the boolean to false to receive the next set of frames.
-            scoped_lock<mutex> lock(mAccessLock);
-            mProcessingEvsFrames = false;
-        }
-    }
-
-    // Notify the SV client that no new results will be delivered.
-    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
-    mStream->notify(SvEvent::STREAM_STOPPED);
-
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-        mStreamState = STOPPED;
-        mStream = nullptr;
-        LOG(DEBUG) << "Stream marked STOPPED.";
-    }
-
-    ATRACE_END();
-}
-
-SurroundView3dSession::SurroundView3dSession(sp<IEvsEnumerator> pEvs,
-                                             VhalHandler* vhalHandler,
-                                             AnimationModule* animationModule,
-                                             IOModuleConfig* pConfig) :
-      mEvs(pEvs),
-      mStreamState(STOPPED),
-      mVhalHandler(vhalHandler),
-      mAnimationModule(animationModule),
-      mIOModuleConfig(pConfig) {}
-
-SurroundView3dSession::~SurroundView3dSession() {
-    // In case the client did not call stopStream properly, we should stop the
-    // stream explicitly. Otherwise the process thread will take forever to
-    // join.
-    stopStream();
-
-    // Waiting for the process thread to finish the buffered frames.
-    if (mProcessThread.joinable()) {
-        mProcessThread.join();
-    }
-
-    mEvs->closeCamera(mCamera);
-}
-
-// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
-Return<SvResult> SurroundView3dSession::startStream(
-    const sp<ISurroundViewStream>& stream) {
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock<mutex> lock(mAccessLock);
-
-    if (!mIsInitialized && !initialize()) {
-        LOG(ERROR) << "There is an error while initializing the use case. "
-                   << "Exiting";
-        return SvResult::INTERNAL_ERROR;
-    }
-
-    if (mStreamState != STOPPED) {
-        LOG(ERROR) << "Ignoring startVideoStream call when a stream is "
-                   << "already running.";
-        return SvResult::INTERNAL_ERROR;
-    }
-
-    if (mViews.empty()) {
-        LOG(ERROR) << "No views have been set for current Surround View"
-                   << "3d Session. Please call setViews before starting"
-                   << "the stream.";
-        return SvResult::VIEW_NOT_SET;
-    }
-
-    if (stream == nullptr) {
-        LOG(ERROR) << "The input stream is invalid";
-        return SvResult::INTERNAL_ERROR;
-    }
-    mStream = stream;
-
-    mSequenceId = 0;
-    startEvs();
-
-    if (mVhalHandler != nullptr) {
-        if (!mVhalHandler->startPropertiesUpdate()) {
-            LOG(WARNING) << "VhalHandler cannot be started properly";
-        }
-    } else {
-        LOG(WARNING) << "VhalHandler is null. Ignored";
-    }
-
-    // TODO(b/158131080): the STREAM_STARTED event is not implemented in EVS
-    // reference implementation yet. Once implemented, this logic should be
-    // moved to EVS notify callback.
-    LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
-    mStream->notify(SvEvent::STREAM_STARTED);
-    mProcessingEvsFrames = false;
-
-    // Start the frame generation thread
-    mStreamState = RUNNING;
-
-    mProcessThread = thread([this]() {
-        processFrames();
-    });
-
-    return SvResult::OK;
-}
-
-Return<void> SurroundView3dSession::stopStream() {
-    LOG(DEBUG) << __FUNCTION__;
-    unique_lock <mutex> lock(mAccessLock);
-
-    if (mVhalHandler != nullptr) {
-        mVhalHandler->stopPropertiesUpdate();
-    } else {
-        LOG(WARNING) << "VhalHandler is null. Ignored";
-    }
-
-    if (mStreamState == RUNNING) {
-        // Tell the processFrames loop to stop processing frames
-        mStreamState = STOPPING;
-
-        // Stop the EVS stream asynchronizely
-        mCamera->stopVideoStream();
-    }
-
-    return {};
-}
-
-Return<void> SurroundView3dSession::doneWithFrames(
-    const SvFramesDesc& svFramesDesc){
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock <mutex> lock(mAccessLock);
-
-    mFramesRecord.inUse = false;
-
-    (void)svFramesDesc;
-    return {};
-}
-
-// Methods from ISurroundView3dSession follow.
-Return<SvResult> SurroundView3dSession::setViews(
-    const hidl_vec<View3d>& views) {
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock <mutex> lock(mAccessLock);
-
-    if (views.size() == 0) {
-        LOG(ERROR) << "Empty view argument, at-least one view is required.";
-        return SvResult::VIEW_NOT_SET;
-    }
-
-    mViews.resize(views.size());
-    for (int i=0; i<views.size(); i++) {
-        mViews[i] = views[i];
-    }
-
-    return SvResult::OK;
-}
-
-Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
-    LOG(DEBUG) << __FUNCTION__;
-    scoped_lock <mutex> lock(mAccessLock);
-
-    if (sv3dConfig.width <=0 || sv3dConfig.width > 4096) {
-        LOG(WARNING) << "The width of 3d config is out of the range (0, 4096]"
-                     << "Ignored!";
-        return SvResult::INVALID_ARG;
-    }
-
-    if (sv3dConfig.height <=0 || sv3dConfig.height > 4096) {
-        LOG(WARNING) << "The height of 3d config is out of the range (0, 4096]"
-                     << "Ignored!";
-        return SvResult::INVALID_ARG;
-    }
-
-    mConfig.width = sv3dConfig.width;
-    mConfig.height = sv3dConfig.height;
-    mConfig.carDetails = sv3dConfig.carDetails;
-
-    if (mStream != nullptr) {
-        LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
-        mStream->notify(SvEvent::CONFIG_UPDATED);
-    }
-
-    return SvResult::OK;
-}
-
-Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-
-    _hidl_cb(mConfig);
-    return {};
-}
-
-bool VerifyAndGetOverlays(const OverlaysData& overlaysData, std::vector<Overlay>* svCoreOverlays) {
-    // Clear the overlays.
-    svCoreOverlays->clear();
-
-    // Check size of shared memory matches overlaysMemoryDesc.
-    const int kVertexSize = 16;
-    const int kIdSize = 2;
-    int memDescSize = 0;
-    for (auto& overlayMemDesc : overlaysData.overlaysMemoryDesc) {
-        memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
-    }
-    if (overlaysData.overlaysMemory.size() < memDescSize) {
-        LOG(ERROR) << "Allocated shared memory size is less than overlaysMemoryDesc size.";
-        return false;
-    }
-
-    // Map memory.
-    sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
-    if(pSharedMemory == nullptr) {
-        LOG(ERROR) << "mapMemory failed.";
-        return false;
-    }
-
-    // Get Data pointer.
-    uint8_t* pData = static_cast<uint8_t*>(
-        static_cast<void*>(pSharedMemory->getPointer()));
-    if (pData == nullptr) {
-        LOG(ERROR) << "Shared memory getPointer() failed.";
-        return false;
-    }
-
-    int idOffset = 0;
-    set<uint16_t> overlayIdSet;
-    for (auto& overlayMemDesc : overlaysData.overlaysMemoryDesc) {
-
-        if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
-            LOG(ERROR) << "Duplicate id within memory descriptor.";
-            svCoreOverlays->clear();
-            return false;
-        }
-        overlayIdSet.insert(overlayMemDesc.id);
-
-        if(overlayMemDesc.verticesCount < 3) {
-            LOG(ERROR) << "Less than 3 vertices.";
-            svCoreOverlays->clear();
-            return false;
-        }
-
-        if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
-                overlayMemDesc.verticesCount % 3 != 0) {
-            LOG(ERROR) << "Triangles primitive does not have vertices "
-                       << "multiple of 3.";
-            svCoreOverlays->clear();
-            return false;
-        }
-
-        const uint16_t overlayId = *((uint16_t*)(pData + idOffset));
-
-        if (overlayId != overlayMemDesc.id) {
-            LOG(ERROR) << "Overlay id mismatch " << overlayId << ", " << overlayMemDesc.id;
-            svCoreOverlays->clear();
-            return false;
-        }
-
-        // Copy over shared memory data to sv core overlays.
-        Overlay svCoreOverlay;
-        svCoreOverlay.id = overlayMemDesc.id;
-        svCoreOverlay.vertices.resize(overlayMemDesc.verticesCount);
-        uint8_t* verticesDataPtr = pData + idOffset + kIdSize;
-        memcpy(svCoreOverlay.vertices.data(), verticesDataPtr,
-                kVertexSize * overlayMemDesc.verticesCount);
-        svCoreOverlays->push_back(svCoreOverlay);
-
-        idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
-    }
-
-    return true;
-}
-
-Return<SvResult>  SurroundView3dSession::updateOverlays(const OverlaysData& overlaysData) {
-    LOG(DEBUG) << __FUNCTION__;
-
-    scoped_lock <mutex> lock(mAccessLock);
-    if(!VerifyAndGetOverlays(overlaysData, &mOverlays)) {
-        LOG(ERROR) << "VerifyAndGetOverlays failed.";
-        return SvResult::INVALID_ARG;
-    }
-
-    mOverlayIsUpdated = true;
-    return SvResult::OK;
-}
-
-Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
-        const hidl_vec<Point2dInt>& cameraPoints, const hidl_string& cameraId,
-        projectCameraPointsTo3dSurface_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-    bool cameraIdFound = false;
-    int cameraIndex = 0;
-    std::vector<Point3dFloat> points3d;
-
-    // Note: mEvsCameraIds must be in the order front, right, rear, left.
-    for (auto& evsCameraId : mEvsCameraIds) {
-        if (cameraId == evsCameraId) {
-            cameraIdFound = true;
-            LOG(DEBUG) << "Camera id found for projection: " << cameraId;
-            break;
-        }
-        cameraIndex++;
-    }
-
-    if (!cameraIdFound) {
-        LOG(ERROR) << "Camera id not found for projection: " << cameraId;
-        _hidl_cb(points3d);
-        return {};
-    }
-
-    for (const auto& cameraPoint : cameraPoints) {
-        Point3dFloat point3d = {false, 0.0, 0.0, 0.0};
-
-        // Verify if camera point is within the camera resolution bounds.
-        const Size2dInteger cameraSize = mCameraParams[cameraIndex].size;
-        point3d.isValid = (cameraPoint.x >= 0 && cameraPoint.x < cameraSize.width &&
-                           cameraPoint.y >= 0 && cameraPoint.y < cameraSize.height);
-        if (!point3d.isValid) {
-            LOG(WARNING) << "Camera point (" << cameraPoint.x << ", " << cameraPoint.y
-                         << ") is out of camera resolution bounds.";
-            points3d.push_back(point3d);
-            continue;
-        }
-
-        // Project points using mSurroundView function.
-        const Coordinate2dInteger camCoord(cameraPoint.x, cameraPoint.y);
-        Coordinate3dFloat projPoint3d(0.0, 0.0, 0.0);
-        point3d.isValid =
-                mSurroundView->GetProjectionPointFromRawCameraToSurroundView3d(camCoord,
-                                                                               cameraIndex,
-                                                                               &projPoint3d);
-        // Convert projPoint3d in meters to point3d which is in milli-meters.
-        point3d.x = projPoint3d.x * 1000.0;
-        point3d.y = projPoint3d.y * 1000.0;
-        point3d.z = projPoint3d.z * 1000.0;
-        points3d.push_back(point3d);
-    }
-    _hidl_cb(points3d);
-    return {};
-}
-
-bool SurroundView3dSession::handleFrames(int sequenceId) {
-    LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
-
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    // TODO(b/157498592): Now only one sets of EVS input frames and one SV
-    // output frame is supported. Implement buffer queue for both of them.
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-
-        if (mFramesRecord.inUse) {
-            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
-            mStream->notify(SvEvent::FRAME_DROPPED);
-            return true;
-        }
-
-        // Release the frames for GPU solution.
-        mCamera->doneWithFrame_1_1(mEvsGraphicBuffers);
-    }
-
-    // If the width/height was changed, re-allocate the Graphic Buffer and
-    // update the Surround View core lib.
-    if (mOutputWidth != mConfig.width
-        || mOutputHeight != mConfig.height) {
-        mOutputWidth = mConfig.width;
-        mOutputHeight = mConfig.height;
-        mOutputPointer.height = mOutputHeight;
-        mOutputPointer.width = mOutputWidth;
-        mOutputPointer.format = Format::RGBA;
-
-        Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
-        mSurroundView->Update3dOutputResolution(size);
-
-        mSvTexture = new GraphicBuffer(mOutputWidth,
-                                       mOutputHeight,
-                                       HAL_PIXEL_FORMAT_RGBA_8888,
-                                       1,
-                                       GRALLOC_USAGE_HW_TEXTURE,
-                                       "SvTexture");
-        if (mSvTexture->initCheck() == OK) {
-            LOG(INFO) << "Successfully allocated Graphic Buffer";
-        } else {
-            LOG(ERROR) << "Failed to allocate Graphic Buffer";
-            return false;
-        }
-    }
-
-    ATRACE_BEGIN("SV core lib method: Set3dOverlay");
-    // Set 3d overlays.
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-        if (mOverlayIsUpdated) {
-            if (!mSurroundView->Set3dOverlay(mOverlays)) {
-                LOG(ERROR) << "Set 3d overlays failed.";
-            }
-            mOverlayIsUpdated = false;
-        }
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("VhalHandler method: getPropertyValues");
-    // Get the latest VHal property values
-    if (mVhalHandler != nullptr) {
-        if (!mVhalHandler->getPropertyValues(&mPropertyValues)) {
-            LOG(ERROR) << "Failed to get property values";
-        }
-    } else {
-        LOG(WARNING) << "VhalHandler is null. Ignored";
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("AnimationModule method: getUpdatedAnimationParams");
-    vector<AnimationParam> params;
-    if (mAnimationModule != nullptr) {
-        params = mAnimationModule->getUpdatedAnimationParams(mPropertyValues);
-    } else {
-        LOG(WARNING) << "AnimationModule is null. Ignored";
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("SV core lib method: SetAnimations");
-    if (!params.empty()) {
-        mSurroundView->SetAnimations(params);
-    } else {
-        LOG(INFO) << "AnimationParams is empty. Ignored";
-    }
-    ATRACE_END();
-
-    // Get the view.
-    // TODO(161399517): Only single view is currently supported, add support for multiple views.
-    const View3d view3d = mViews[0];
-    const RotationQuat quat = view3d.pose.rotation;
-    const Translation trans = view3d.pose.translation;
-    const std::array<float, 4> viewQuaternion = {quat.x, quat.y, quat.z, quat.w};
-    const std::array<float, 3> viewTranslation = {trans.x, trans.y, trans.z};
-
-    ATRACE_BEGIN("SV core lib method: Get3dSurroundView");
-    if (mSurroundView->Get3dSurroundView(
-            mInputPointers, viewQuaternion, viewTranslation, &mOutputPointer)) {
-        LOG(INFO) << "Get3dSurroundView succeeded";
-    } else {
-        LOG(ERROR) << "Get3dSurroundView failed. "
-                   << "Using memset to initialize to gray.";
-        memset(mOutputPointer.cpu_data_pointer, kGrayColor,
-               mOutputHeight * mOutputWidth * kOutputNumChannels);
-    }
-    ATRACE_END();
-
-    // Release the frames for GPU solution.
-    ATRACE_BEGIN("Release the evs frames");
-    mCamera->doneWithFrame_1_1(mEvsGraphicBuffers);
-    ATRACE_END();
-
-    ATRACE_BEGIN("Lock output texture (gpu to cpu)");
-    void* textureDataPtr = nullptr;
-    mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
-                    | GRALLOC_USAGE_SW_READ_NEVER,
-                    &textureDataPtr);
-    ATRACE_END();
-
-    if (!textureDataPtr) {
-        LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
-        return false;
-    }
-
-    ATRACE_BEGIN("Copy output result");
-    // Note: there is a chance that the stride of the texture is not the
-    // same as the width. For example, when the input frame is 1920 * 1080,
-    // the width is 1080, but the stride is 2048. So we'd better copy the
-    // data line by line, instead of single memcpy.
-    uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
-    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.cpu_data_pointer);
-    const int readStride = mOutputWidth * kOutputNumChannels;
-    const int writeStride = mSvTexture->getStride() * kOutputNumChannels;
-    if (readStride == writeStride) {
-        memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
-    } else {
-        for (int i=0; i<mSvTexture->getHeight(); i++) {
-            memcpy(writePtr, readPtr, readStride);
-            writePtr = writePtr + writeStride;
-            readPtr = readPtr + readStride;
-        }
-    }
-    LOG(INFO) << "memcpy finished!";
-    ATRACE_END();
-
-    ATRACE_BEGIN("Unlock output texture (cpu to gpu)");
-    mSvTexture->unlock();
-    ATRACE_END();
-
-    ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
-    LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
-
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-
-        mFramesRecord.frames.svBuffers.resize(1);
-        SvBuffer& svBuffer = mFramesRecord.frames.svBuffers[0];
-        svBuffer.viewId = 0;
-        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
-        AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<AHardwareBuffer_Desc *>(
-                &svBuffer.hardwareBuffer.description);
-        pDesc->width = mOutputWidth;
-        pDesc->height = mOutputHeight;
-        pDesc->layers = 1;
-        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
-        pDesc->stride = mSvTexture->getStride();
-        pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
-        mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
-        mFramesRecord.frames.sequenceId = sequenceId;
-
-        mFramesRecord.inUse = true;
-        mStream->receiveFrames(mFramesRecord.frames);
-    }
-
-    ATRACE_END();
-
-    return true;
-}
-
-bool SurroundView3dSession::initialize() {
-    lock_guard<mutex> lock(mAccessLock, adopt_lock);
-
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    if (!setupEvs()) {
-        LOG(ERROR) << "Failed to setup EVS components for 3d session";
-        return false;
-    }
-
-    // TODO(b/150412555): ask core-lib team to add API description for "create"
-    // method in the .h file.
-    // The create method will never return a null pointer based the API
-    // description.
-    mSurroundView = unique_ptr<SurroundView>(Create());
-
-    SurroundViewStaticDataParams params =
-            SurroundViewStaticDataParams(
-                    mCameraParams,
-                    mIOModuleConfig->sv2dConfig.sv2dParams,
-                    mIOModuleConfig->sv3dConfig.sv3dParams,
-                    vector<float>(std::begin(kUndistortionScales),
-                                  std::end(kUndistortionScales)),
-                    mIOModuleConfig->sv2dConfig.carBoundingBox,
-                    mIOModuleConfig->carModelConfig.carModel.texturesMap,
-                    mIOModuleConfig->carModelConfig.carModel.partsMap);
-    ATRACE_BEGIN("SV core lib method: SetStaticData");
-    mSurroundView->SetStaticData(params);
-    ATRACE_END();
-
-    ATRACE_BEGIN("Allocate cpu buffers");
-
-    mInputPointers.resize(kNumFrames);
-    for (int i = 0; i < kNumFrames; i++) {
-        // We do not need to explicitly allocate cpu_data_pointer any more since the
-        // input data handling is purely on GPU side now.
-        mInputPointers[i].width = mCameraParams[i].size.width;
-        mInputPointers[i].height = mCameraParams[i].size.height;
-        mInputPointers[i].format = Format::RGBA;
-    }
-
-    mOutputWidth = mIOModuleConfig->sv3dConfig.sv3dParams.resolution.width;
-    mOutputHeight = mIOModuleConfig->sv3dConfig.sv3dParams.resolution.height;
-
-    mConfig.width = mOutputWidth;
-    mConfig.height = mOutputHeight;
-    mConfig.carDetails = SvQuality::HIGH;
-
-    mOutputPointer.height = mOutputHeight;
-    mOutputPointer.width = mOutputWidth;
-    mOutputPointer.format = Format::RGBA;
-    mOutputPointer.cpu_data_pointer =
-            static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
-
-    if (!mOutputPointer.cpu_data_pointer) {
-        LOG(ERROR) << "Memory allocation failed. Exiting.";
-        return false;
-    }
-    ATRACE_END();
-
-    ATRACE_BEGIN("Allocate output texture");
-    mSvTexture = new GraphicBuffer(mOutputWidth,
-                                   mOutputHeight,
-                                   HAL_PIXEL_FORMAT_RGBA_8888,
-                                   1,
-                                   GRALLOC_USAGE_HW_TEXTURE,
-                                   "SvTexture");
-
-    if (mSvTexture->initCheck() == OK) {
-        LOG(INFO) << "Successfully allocated Graphic Buffer";
-    } else {
-        LOG(ERROR) << "Failed to allocate Graphic Buffer";
-        return false;
-    }
-    ATRACE_END();
-
-    mIsInitialized = true;
-
-    ATRACE_END();
-
-    return true;
-}
-
-bool SurroundView3dSession::setupEvs() {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    // Reads the camera related information from the config object
-    const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
-
-    // Setup for EVS
-    LOG(INFO) << "Requesting camera list";
-    mEvs->getCameraList_1_1(
-            [this, evsGroupId] (hidl_vec<CameraDesc> cameraList) {
-        LOG(INFO) << "Camera list callback received " << cameraList.size();
-        for (auto&& cam : cameraList) {
-            LOG(INFO) << "Found camera " << cam.v1.cameraId;
-            if (cam.v1.cameraId == evsGroupId) {
-                mCameraDesc = cam;
-            }
-        }
-    });
-
-    bool foundCfg = false;
-    std::unique_ptr<Stream> targetCfg(new Stream());
-
-    // This logic picks the configuration with the largest area that supports
-    // RGBA8888 format
-    int32_t maxArea = 0;
-    camera_metadata_entry_t streamCfgs;
-    if (!find_camera_metadata_entry(
-             reinterpret_cast<camera_metadata_t *>(mCameraDesc.metadata.data()),
-             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-             &streamCfgs)) {
-        // Stream configurations are found in metadata
-        RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(
-            streamCfgs.data.i32);
-        for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
-            if (ptr->direction ==
-                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
-                ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
-
-                if (ptr->width * ptr->height > maxArea) {
-                    targetCfg->id = ptr->id;
-                    targetCfg->width = ptr->width;
-                    targetCfg->height = ptr->height;
-
-                    // This client always wants below input data format
-                    targetCfg->format =
-                        static_cast<GraphicsPixelFormat>(
-                            HAL_PIXEL_FORMAT_RGBA_8888);
-
-                    maxArea = ptr->width * ptr->height;
-
-                    foundCfg = true;
-                }
-            }
-            ++ptr;
-        }
-    } else {
-        LOG(WARNING) << "No stream configuration data is found; "
-                     << "default parameters will be used.";
-    }
-
-    if (!foundCfg) {
-        LOG(INFO) << "No config was found";
-        targetCfg = nullptr;
-        return false;
-    }
-
-    string camId = mCameraDesc.v1.cameraId.c_str();
-    mCamera = mEvs->openCamera_1_1(camId.c_str(), *targetCfg);
-    if (mCamera == nullptr) {
-        LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
-        return false;
-    } else {
-        LOG(INFO) << "Logical camera " << camId << " is opened successfully";
-    }
-
-    mEvsCameraIds = mIOModuleConfig->cameraConfig.evsCameraIds;
-    if (mEvsCameraIds.size() < kNumFrames) {
-        LOG(ERROR) << "Incorrect camera info is stored in the camera config";
-        return false;
-    }
-
-    map<string, AndroidCameraParams> cameraIdToAndroidParameters;
-    for (const auto& id : mEvsCameraIds) {
-        AndroidCameraParams params;
-        if (getAndroidCameraParams(mCamera, id, params)) {
-            cameraIdToAndroidParameters.emplace(id, params);
-            LOG(INFO) << "Camera parameters are fetched successfully for "
-                      << "physical camera: " << id;
-        } else {
-            LOG(ERROR) << "Failed to get camera parameters for "
-                       << "physical camera: " << id;
-            return false;
-        }
-    }
-
-    mCameraParams =
-            convertToSurroundViewCameraParams(cameraIdToAndroidParameters);
-
-    for (auto& camera : mCameraParams) {
-        camera.size.width = targetCfg->width;
-        camera.size.height = targetCfg->height;
-        camera.circular_fov = 179;
-    }
-
-    // Add validity mask filenames.
-    for (int i = 0; i < mCameraParams.size(); i++) {
-        mCameraParams[i].validity_mask_filename = mIOModuleConfig->cameraConfig.maskFilenames[i];
-    }
-    ATRACE_END();
-    return true;
-}
-
-bool SurroundView3dSession::startEvs() {
-    ATRACE_BEGIN(__PRETTY_FUNCTION__);
-
-    mFramesHandler = new FramesHandler(mCamera, this);
-    Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
-    if (result != EvsResult::OK) {
-        LOG(ERROR) << "Failed to start video stream";
-        return false;
-    } else {
-        LOG(INFO) << "Video stream was started successfully";
-    }
-
-    ATRACE_END();
-
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundView3dSession.h b/cpp/surround_view/service-impl/SurroundView3dSession.h
deleted file mode 100644
index 39bcfb8..0000000
--- a/cpp/surround_view/service-impl/SurroundView3dSession.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/sv/1.0/types.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
-
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include "AnimationModule.h"
-#include "VhalHandler.h"
-
-#include <thread>
-
-#include <ui/GraphicBuffer.h>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using namespace ::android::hardware::automotive::sv::V1_0;
-using namespace ::android::hardware::automotive::vehicle::V2_0;
-using namespace ::android_auto::surround_view;
-
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
-using ::android::sp;
-using ::std::condition_variable;
-
-using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-class SurroundView3dSession : public ISurroundView3dSession {
-
-    /*
-     * FramesHandler:
-     * This class can be used to receive camera imagery from an IEvsCamera implementation.  It will
-     * hold onto the most recent image buffer, returning older ones.
-     * Note that the video frames are delivered on a background thread, while the control interface
-     * is actuated from the applications foreground thread.
-     */
-    class FramesHandler : public IEvsCameraStream {
-    public:
-        FramesHandler(sp<IEvsCamera> pCamera, sp<SurroundView3dSession> pSession);
-
-    private:
-        // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
-        Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
-
-        // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
-        Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
-        Return<void> notify(const EvsEventDesc& event) override;
-
-        // Values initialized as startup
-        sp<IEvsCamera> mCamera;
-
-        sp<SurroundView3dSession> mSession;
-    };
-
-public:
-    // TODO(b/158479099): use strong pointer for VhalHandler
-    SurroundView3dSession(sp<IEvsEnumerator> pEvs,
-                          VhalHandler* vhalHandler,
-                          AnimationModule* animationModule,
-                          IOModuleConfig* pConfig);
-    ~SurroundView3dSession();
-    bool initialize();
-
-    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
-    Return<SvResult> startStream(
-        const sp<ISurroundViewStream>& stream) override;
-    Return<void> stopStream() override;
-    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
-
-    // Methods from ISurroundView3dSession follow.
-    Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
-    Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
-    Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
-    Return<SvResult>  updateOverlays(const OverlaysData& overlaysData);
-    Return<void> projectCameraPointsTo3dSurface(
-        const hidl_vec<Point2dInt>& cameraPoints,
-        const hidl_string& cameraId,
-        projectCameraPointsTo3dSurface_cb _hidl_cb);
-
-private:
-    void processFrames();
-
-    // Set up and open the Evs camera(s), triggered when session is created.
-    bool setupEvs();
-
-    // Start Evs camera video stream, triggered when SV stream is started.
-    bool startEvs();
-
-    bool handleFrames(int sequenceId);
-
-    enum StreamStateValues {
-        STOPPED,
-        RUNNING,
-        STOPPING,
-        DEAD,
-    };
-
-    // EVS Enumerator to control the start/stop of the Evs Stream
-    sp<IEvsEnumerator> mEvs;
-
-    // Instance and metadata for the opened Evs Camera
-    sp<IEvsCamera> mCamera;
-    CameraDesc mCameraDesc;
-    std::vector<SurroundViewCameraParams> mCameraParams;
-
-    // Stream subscribed for the session.
-    sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
-    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
-
-    std::thread mProcessThread; // The thread we'll use to process frames
-
-    // Reference to the inner class, to handle the incoming Evs frames
-    sp<FramesHandler> mFramesHandler;
-
-    // Used to signal a set of frames is ready
-    condition_variable mFramesSignal GUARDED_BY(mAccessLock);
-    bool mProcessingEvsFrames GUARDED_BY(mAccessLock);
-
-    int mSequenceId;
-
-    struct FramesRecord {
-        SvFramesDesc frames;
-        bool inUse = false;
-    };
-
-    FramesRecord mFramesRecord GUARDED_BY(mAccessLock);
-
-    // Synchronization necessary to deconflict mCaptureThread from the main service thread
-    std::mutex mAccessLock;
-
-    std::vector<View3d> mViews GUARDED_BY(mAccessLock);
-
-    Sv3dConfig mConfig GUARDED_BY(mAccessLock);
-
-    std::vector<std::string> mEvsCameraIds GUARDED_BY(mAccessLock);
-
-    std::unique_ptr<SurroundView> mSurroundView GUARDED_BY(mAccessLock);
-
-    std::vector<SurroundViewInputBufferPointers>
-        mInputPointers GUARDED_BY(mAccessLock);
-    SurroundViewResultPointer mOutputPointer GUARDED_BY(mAccessLock);
-    int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
-
-    sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
-
-    bool mIsInitialized GUARDED_BY(mAccessLock) = false;
-
-    VhalHandler* mVhalHandler;
-    AnimationModule* mAnimationModule;
-    IOModuleConfig* mIOModuleConfig;
-
-    std::vector<Overlay> mOverlays GUARDED_BY(mAccessLock);
-    bool mOverlayIsUpdated GUARDED_BY(mAccessLock) = false;
-
-    std::vector<VehiclePropValue> mPropertyValues;
-
-    hidl_vec<BufferDesc_1_1> mEvsGraphicBuffers;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundView3dSessionTests.cpp b/cpp/surround_view/service-impl/SurroundView3dSessionTests.cpp
deleted file mode 100644
index afe8f07..0000000
--- a/cpp/surround_view/service-impl/SurroundView3dSessionTests.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "SurroundView3dSessionTests"
-
-#include "AnimationModule.h"
-#include "IOModule.h"
-#include "SurroundView3dSession.h"
-#include "VhalHandler.h"
-#include "mock-evs/MockEvsEnumerator.h"
-#include "mock-evs/MockSurroundViewCallback.h"
-
-#include <android-base/logging.h>
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <gtest/gtest.h>
-#include <hidlmemory/mapping.h>
-
-#include <time.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-using ::android::sp;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::automotive::sv::V1_0::OverlayMemoryDesc;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-
-const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
-
-// Sv 3D output height and width set by the config file.
-const int kSv3dWidth = 1920;
-const int kSv3dHeight = 1080;
-
-// Constants for overlays.
-const int kVertexByteSize = (3 * sizeof(float)) + 4;
-const int kIdByteSize = 2;
-
-class SurroundView3dSessionTests : public ::testing::Test {
-protected:
-    // Setup sv3d session without vhal and animations.
-    void SetupSv3dSession() {
-        mFakeEvs = new MockEvsEnumerator();
-        mIoModule = new IOModule(kSvConfigFilename);
-        EXPECT_EQ(mIoModule->initialize(), IOStatus::OK);
-
-        mIoModule->getConfig(&mIoModuleConfig);
-
-        mSv3dSession = new SurroundView3dSession(mFakeEvs, nullptr,
-                                                 nullptr,
-                                                 &mIoModuleConfig);
-
-        EXPECT_TRUE(mSv3dSession->initialize());
-        mSv3dCallback = new MockSurroundViewCallback(mSv3dSession);
-        vector<View3d> views = {
-        {
-            .viewId = 0,
-            .pose = {
-                .rotation = {.x = 0, .y = 0, .z = 0, .w = 1.0f},
-                .translation = {.x = 0, .y = 0, .z = 0},
-            },
-            .horizontalFov = 90,
-        }};
-        mSv3dSession->setViews(views);
-    }
-
-    // Setup sv3d session with vhal and animations.
-    void SetupSv3dSessionVhalAnimation() {
-        mFakeEvs = new MockEvsEnumerator();
-        mIoModule = new IOModule(kSvConfigFilename);
-        EXPECT_EQ(mIoModule->initialize(), IOStatus::OK);
-
-        mIoModule->getConfig(&mIoModuleConfig);
-
-        mVhalHandler = new VhalHandler();
-        ASSERT_TRUE(mVhalHandler->initialize(VhalHandler::UpdateMethod::GET, 10));
-
-        mAnimationModule = new AnimationModule(mIoModuleConfig.carModelConfig.carModel.partsMap,
-                                    mIoModuleConfig.carModelConfig.carModel.texturesMap,
-                                    mIoModuleConfig.carModelConfig.animationConfig.animations);
-
-        const std::vector<uint64_t> animationPropertiesToRead =
-                getAnimationPropertiesToRead(mIoModuleConfig.carModelConfig.animationConfig);
-        ASSERT_TRUE(mVhalHandler->setPropertiesToRead(animationPropertiesToRead));
-
-        mSv3dSessionAnimations = new SurroundView3dSession(mFakeEvs, mVhalHandler,
-                                                 mAnimationModule,
-                                                 &mIoModuleConfig);
-
-        EXPECT_TRUE(mSv3dSessionAnimations->initialize());
-
-        mSv3dCallbackAnimations = new MockSurroundViewCallback(mSv3dSessionAnimations);
-        vector<View3d> views = {
-        // View 0
-        {
-            .viewId = 0,
-            .pose = {
-                .rotation = {.x = 0, .y = 0, .z = 0, .w = 1.0f},
-                .translation = {.x = 0, .y = 0, .z = 0},
-            },
-            .horizontalFov = 90,
-        }};
-
-        mSv3dSessionAnimations->setViews(views);
-    }
-
-    // Helper function to get list of vhal properties to read from car config file for animations.
-    std::vector<uint64_t> getAnimationPropertiesToRead(const AnimationConfig& animationConfig) {
-        std::set<uint64_t> propertiesSet;
-        for (const auto& animation : animationConfig.animations) {
-            for (const auto& opPair : animation.gammaOpsMap) {
-                propertiesSet.insert(opPair.first);
-            }
-
-            for (const auto& opPair : animation.textureOpsMap) {
-                propertiesSet.insert(opPair.first);
-            }
-
-            for (const auto& opPair : animation.rotationOpsMap) {
-                propertiesSet.insert(opPair.first);
-            }
-
-            for (const auto& opPair : animation.translationOpsMap) {
-                propertiesSet.insert(opPair.first);
-            }
-        }
-        std::vector<uint64_t> propertiesToRead;
-        propertiesToRead.assign(propertiesSet.begin(), propertiesSet.end());
-        return propertiesToRead;
-    }
-
-    void TearDown() override {
-        mSv3dSession = nullptr;
-        mFakeEvs = nullptr;
-        mSv3dCallback = nullptr;
-        delete mVhalHandler;
-        delete mAnimationModule;
-        delete mIoModule;
-    }
-
-    sp<IEvsEnumerator> mFakeEvs;
-    IOModule* mIoModule;
-    IOModuleConfig mIoModuleConfig;
-    sp<SurroundView3dSession> mSv3dSession;
-    sp<MockSurroundViewCallback> mSv3dCallback;
-
-    VhalHandler* mVhalHandler;
-    AnimationModule* mAnimationModule;
-    sp<SurroundView3dSession> mSv3dSessionAnimations;
-    sp<MockSurroundViewCallback> mSv3dCallbackAnimations;
-};
-
-TEST_F(SurroundView3dSessionTests, startAndStop3dSession) {
-    SetupSv3dSession();
-    EXPECT_EQ(mSv3dSession->startStream(mSv3dCallback), SvResult::OK);
-    sleep(5);
-    mSv3dSession->stopStream();
-    EXPECT_GT(mSv3dCallback->getReceivedFramesCount(), 0);
-}
-
-TEST_F(SurroundView3dSessionTests, get3dConfigSuccess) {
-    SetupSv3dSession();
-    Sv3dConfig sv3dConfig;
-    mSv3dSession->get3dConfig([&sv3dConfig](const Sv3dConfig& config) { sv3dConfig = config; });
-
-    EXPECT_EQ(sv3dConfig.width, kSv3dWidth);
-    EXPECT_EQ(sv3dConfig.height, kSv3dHeight);
-    EXPECT_EQ(sv3dConfig.carDetails, SvQuality::HIGH);
-}
-
-// Sets a different config and checks of the received config matches.
-TEST_F(SurroundView3dSessionTests, setAndGet3dConfigSuccess) {
-    SetupSv3dSession();
-    Sv3dConfig sv3dConfigSet = {kSv3dWidth / 2, kSv3dHeight / 2, SvQuality::LOW};
-
-    EXPECT_EQ(mSv3dSession->set3dConfig(sv3dConfigSet), SvResult::OK);
-
-    Sv3dConfig sv3dConfigReceived;
-    mSv3dSession->get3dConfig(
-            [&sv3dConfigReceived](const Sv3dConfig& config) { sv3dConfigReceived = config; });
-
-    EXPECT_EQ(sv3dConfigReceived.width, sv3dConfigSet.width);
-    EXPECT_EQ(sv3dConfigReceived.height, sv3dConfigSet.height);
-    EXPECT_EQ(sv3dConfigReceived.carDetails, sv3dConfigSet.carDetails);
-}
-
-// Projects center of each cameras and checks if valid projected point is received.
-TEST_F(SurroundView3dSessionTests, projectPoints3dSuccess) {
-    SetupSv3dSession();
-    hidl_vec<Point2dInt> points2dCamera = {
-            /*Center point*/ {.x = kSv3dWidth / 2, .y = kSv3dHeight / 2}};
-
-    std::vector<hidl_string> cameraIds = {"/dev/video60", "/dev/video61", "/dev/video62",
-                                          "/dev/video63"};
-
-    for (int i = 0; i < cameraIds.size(); i++) {
-        mSv3dSession
-                ->projectCameraPointsTo3dSurface(points2dCamera, cameraIds[i],
-                                                 [](const hidl_vec<Point3dFloat>& projectedPoints) {
-                                                     EXPECT_TRUE(projectedPoints[0].isValid);
-                                                 });
-    }
-}
-
-std::pair<hidl_memory, sp<IMemory>> GetMappedSharedMemory(int bytesSize) {
-    const auto nullResult = std::make_pair(hidl_memory(), nullptr);
-
-    sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
-    if (ashmemAllocator.get() == nullptr) {
-        return nullResult;
-    }
-
-    // Allocate shared memory.
-    hidl_memory hidlMemory;
-    bool allocateSuccess = false;
-    Return<void> result =
-            ashmemAllocator->allocate(bytesSize, [&](bool success, const hidl_memory& hidlMem) {
-                if (!success) {
-                    return;
-                }
-                allocateSuccess = success;
-                hidlMemory = hidlMem;
-            });
-
-    // Check result of allocated memory.
-    if (!result.isOk() || !allocateSuccess) {
-        return nullResult;
-    }
-
-    // Map shared memory.
-    sp<IMemory> pIMemory = mapMemory(hidlMemory);
-    if (pIMemory.get() == nullptr) {
-        return nullResult;
-    }
-
-    return std::make_pair(hidlMemory, pIMemory);
-}
-
-void SetIndexOfOverlaysMemory(const std::vector<OverlayMemoryDesc>& overlaysMemDesc,
-                              sp<IMemory> pIMemory, int indexPosition, uint16_t indexValue) {
-    // Count the number of vertices until the index.
-    int totalVerticesCount = 0;
-    for (int i = 0; i < indexPosition; i++) {
-        totalVerticesCount += overlaysMemDesc[i].verticesCount;
-    }
-
-    const int indexBytePosition =
-            (indexPosition * kIdByteSize) + (kVertexByteSize * totalVerticesCount);
-
-    uint8_t* pSharedMemoryData = reinterpret_cast<uint8_t*>((void*)pIMemory->getPointer());
-    pSharedMemoryData += indexBytePosition;
-    uint16_t* pIndex16bit = reinterpret_cast<uint16_t*>(pSharedMemoryData);
-
-    // Modify shared memory.
-    pIMemory->update();
-    *pIndex16bit = indexValue;
-    pIMemory->commit();
-}
-
-std::pair<OverlaysData, sp<IMemory>> GetSampleOverlaysData() {
-    OverlaysData overlaysData;
-    overlaysData.overlaysMemoryDesc.resize(2);
-
-    int sharedMemBytesSize = 0;
-    OverlayMemoryDesc overlayMemDesc1, overlayMemDesc2;
-    overlayMemDesc1.id = 0;
-    overlayMemDesc1.verticesCount = 6;
-    overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
-    overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
-    sharedMemBytesSize += kIdByteSize + kVertexByteSize * overlayMemDesc1.verticesCount;
-
-    overlayMemDesc2.id = 1;
-    overlayMemDesc2.verticesCount = 4;
-    overlayMemDesc2.overlayPrimitive = OverlayPrimitive::TRIANGLES_STRIP;
-    overlaysData.overlaysMemoryDesc[1] = overlayMemDesc2;
-    sharedMemBytesSize += kIdByteSize + kVertexByteSize * overlayMemDesc2.verticesCount;
-
-    std::pair<hidl_memory, sp<IMemory>> sharedMem = GetMappedSharedMemory(sharedMemBytesSize);
-    sp<IMemory> pIMemory = sharedMem.second;
-    if (pIMemory.get() == nullptr) {
-        return std::make_pair(OverlaysData(), nullptr);
-    }
-
-    // Get pointer to shared memory data and set all bytes to 0.
-    uint8_t* pSharedMemoryData = reinterpret_cast<uint8_t*>((void*)pIMemory->getPointer());
-    pIMemory->update();
-    memset(pSharedMemoryData, 0, sharedMemBytesSize);
-    pIMemory->commit();
-
-    std::vector<OverlayMemoryDesc> overlaysDesc = {overlayMemDesc1, overlayMemDesc2};
-
-    // Set indexes in shared memory.
-    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
-    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlayMemDesc2.id);
-
-    overlaysData.overlaysMemoryDesc = overlaysDesc;
-    overlaysData.overlaysMemory = sharedMem.first;
-
-    return std::make_pair(overlaysData, pIMemory);
-}
-
-// Verifies a valid overlay can be updated while streaming.
-TEST_F(SurroundView3dSessionTests, updateOverlaysSuccess) {
-    SetupSv3dSession();
-    std::pair<OverlaysData, sp<IMemory>> overlaysData = GetSampleOverlaysData();
-    ASSERT_NE(overlaysData.second, nullptr);
-    EXPECT_EQ(mSv3dSession->startStream(mSv3dCallback), SvResult::OK);
-    SvResult result = mSv3dSession->updateOverlays(overlaysData.first);
-    mSv3dSession->stopStream();
-    EXPECT_EQ(result, SvResult::OK);
-}
-
-// Setup sv 3d sessin with vhal and animations and verify frames are received successfully.
-TEST_F(SurroundView3dSessionTests, vhalAnimationSuccess) {
-    SetupSv3dSessionVhalAnimation();
-    EXPECT_EQ(mSv3dSessionAnimations->startStream(mSv3dCallbackAnimations), SvResult::OK);
-    sleep(5);
-    mSv3dSessionAnimations->stopStream();
-    EXPECT_GT(mSv3dCallbackAnimations->getReceivedFramesCount(), 0);
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundViewService.cpp b/cpp/surround_view/service-impl/SurroundViewService.cpp
deleted file mode 100644
index e8a2ffd..0000000
--- a/cpp/surround_view/service-impl/SurroundViewService.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include <android-base/logging.h>
-
-#include "SurroundViewService.h"
-
-using namespace android_auto::surround_view;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-std::mutex SurroundViewService::sLock;
-sp<SurroundViewService> SurroundViewService::sService;
-sp<SurroundView2dSession> SurroundViewService::sSurroundView2dSession;
-sp<SurroundView3dSession> SurroundViewService::sSurroundView3dSession;
-
-const std::string kCameraIds[] = {"0", "1", "2", "3"};
-static const int kVhalUpdateRate = 10;
-
-SurroundViewService::SurroundViewService() :
-      mVhalHandler(nullptr), mAnimationModule(nullptr), mIOModule(nullptr) {
-    mVhalHandler = new VhalHandler();
-    mIOModule = new IOModule("/vendor/etc/automotive/sv/sv_sample_config.xml");
-}
-
-SurroundViewService::~SurroundViewService() {
-    if (mVhalHandler != nullptr) {
-        delete mVhalHandler;
-    }
-
-    if (mIOModule != nullptr) {
-        delete mIOModule;
-    }
-
-    if (mAnimationModule != nullptr) {
-        delete mAnimationModule;
-    }
-}
-
-sp<SurroundViewService> SurroundViewService::getInstance() {
-    std::scoped_lock<std::mutex> lock(sLock);
-    if (sService == nullptr) {
-        sService = new SurroundViewService();
-        if (!sService->initialize()) {
-            LOG(ERROR) << "Cannot initialize the service properly";
-            sService = nullptr;
-            return nullptr;
-        }
-    }
-    return sService;
-}
-
-std::vector<uint64_t> getAnimationPropertiesToRead(const AnimationConfig& animationConfig) {
-    std::set<uint64_t> propertiesSet;
-    for(const auto& animation: animationConfig.animations) {
-        for(const auto& opPair : animation.gammaOpsMap) {
-            propertiesSet.insert(opPair.first);
-        }
-
-        for(const auto& opPair : animation.textureOpsMap) {
-            propertiesSet.insert(opPair.first);
-        }
-
-        for(const auto& opPair : animation.rotationOpsMap) {
-            propertiesSet.insert(opPair.first);
-        }
-
-        for(const auto& opPair : animation.translationOpsMap) {
-            propertiesSet.insert(opPair.first);
-        }
-    }
-    std::vector<uint64_t> propertiesToRead;
-    propertiesToRead.assign(propertiesSet.begin(), propertiesSet.end());
-    return propertiesToRead;
-}
-
-bool SurroundViewService::initialize() {
-    // Get the EVS manager service
-    LOG(INFO) << "Acquiring EVS Enumerator";
-    mEvs = IEvsEnumerator::getService("default");
-    if (mEvs == nullptr) {
-        LOG(ERROR) << "getService returned NULL.  Exiting.";
-        return false;
-    }
-
-    IOStatus status = mIOModule->initialize();
-    if (status != IOStatus::OK) {
-        LOG(ERROR) << "IO Module cannot be initialized properly";
-        return false;
-    }
-
-    if (!mIOModule->getConfig(&mConfig)) {
-        LOG(ERROR) << "Cannot parse Car Config file properly";
-        return false;
-    }
-
-    // Since we only keep one instance of the SurroundViewService and initialize
-    // method is always called after the constructor, it is safe to put the
-    // allocation here and the de-allocation in service's constructor.
-    mAnimationModule = new AnimationModule(
-            mConfig.carModelConfig.carModel.partsMap,
-            mConfig.carModelConfig.carModel.texturesMap,
-            mConfig.carModelConfig.animationConfig.animations);
-
-    // Initialize the VHal Handler with update method and rate.
-    // TODO(b/157498592): The update rate should align with the EVS camera
-    // update rate.
-    if (mVhalHandler->initialize(VhalHandler::GET, kVhalUpdateRate)) {
-        // Initialize the vhal handler properties to read.
-        std::vector<uint64_t> propertiesToRead;
-
-        // Add animation properties to read if 3d and animations are enabled.
-        if (mConfig.sv3dConfig.sv3dEnabled && mConfig.sv3dConfig.sv3dAnimationsEnabled) {
-            const std::vector<uint64_t> animationPropertiesToRead =
-                    getAnimationPropertiesToRead(mConfig.carModelConfig.animationConfig);
-            propertiesToRead.insert(propertiesToRead.end(), animationPropertiesToRead.begin(),
-                    animationPropertiesToRead.end());
-        }
-
-        // Call vhal handler setPropertiesToRead with all properties.
-        if (!mVhalHandler->setPropertiesToRead(propertiesToRead)) {
-            LOG(WARNING) << "VhalHandler setPropertiesToRead failed.";
-        }
-    } else {
-        LOG(WARNING) << "VhalHandler cannot be initialized properly";
-    }
-
-    return true;
-}
-
-Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
-    hidl_vec<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
-        kCameraIds[2], kCameraIds[3]};
-    _hidl_cb(cameraIds);
-    return {};
-}
-
-Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(sLock);
-
-    if (sSurroundView2dSession != nullptr) {
-        LOG(WARNING) << "Only one 2d session is supported at the same time";
-        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
-    } else {
-        sSurroundView2dSession = new SurroundView2dSession(mEvs, &mConfig);
-        if (sSurroundView2dSession->initialize()) {
-            _hidl_cb(sSurroundView2dSession, SvResult::OK);
-        } else {
-            _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
-        }
-    }
-    return {};
-}
-
-Return<SvResult> SurroundViewService::stop2dSession(
-    const sp<ISurroundView2dSession>& sv2dSession) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(sLock);
-
-    if (sv2dSession != nullptr && sv2dSession == sSurroundView2dSession) {
-        sSurroundView2dSession = nullptr;
-        return SvResult::OK;
-    } else {
-        LOG(ERROR) << __FUNCTION__ << ": Invalid argument";
-        return SvResult::INVALID_ARG;
-    }
-}
-
-Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(sLock);
-
-    if (sSurroundView3dSession != nullptr) {
-        LOG(WARNING) << "Only one 3d session is supported at the same time";
-        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
-    } else {
-        sSurroundView3dSession = new SurroundView3dSession(mEvs,
-                                                           mVhalHandler,
-                                                           mAnimationModule,
-                                                           &mConfig);
-        if (sSurroundView3dSession->initialize()) {
-            _hidl_cb(sSurroundView3dSession, SvResult::OK);
-        } else {
-            _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
-        }
-    }
-    return {};
-}
-
-Return<SvResult> SurroundViewService::stop3dSession(
-    const sp<ISurroundView3dSession>& sv3dSession) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(sLock);
-
-    if (sv3dSession != nullptr && sv3dSession == sSurroundView3dSession) {
-        sSurroundView3dSession = nullptr;
-        return SvResult::OK;
-    } else {
-        LOG(ERROR) << __FUNCTION__ << ": Invalid argument";
-        return SvResult::INVALID_ARG;
-    }
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundViewService.h b/cpp/surround_view/service-impl/SurroundViewService.h
deleted file mode 100644
index 6950a27..0000000
--- a/cpp/surround_view/service-impl/SurroundViewService.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include "SurroundView2dSession.h"
-#include "SurroundView3dSession.h"
-#include "AnimationModule.h"
-#include "IOModule.h"
-#include "VhalHandler.h"
-
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/sv/1.0/types.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <thread>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using namespace ::android::hardware::automotive::sv::V1_0;
-using ::android::hardware::Return;
-using ::android::sp;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-class SurroundViewService : public ISurroundViewService {
-public:
-    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
-    Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
-    Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
-    Return<SvResult> stop2dSession(
-        const sp<ISurroundView2dSession>& sv2dSession) override;
-
-    Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
-    Return<SvResult> stop3dSession(
-        const sp<ISurroundView3dSession>& sv3dSession) override;
-
-    static sp<SurroundViewService> getInstance();
-private:
-    SurroundViewService();
-    ~SurroundViewService();
-
-    VhalHandler* mVhalHandler;
-    AnimationModule* mAnimationModule;
-    IOModule* mIOModule;
-    IOModuleConfig mConfig;
-
-    bool initialize();
-    sp<IEvsEnumerator> mEvs;
-
-    static std::mutex sLock;
-    static sp<SurroundViewService> sService GUARDED_BY(sLock);
-
-    static sp<SurroundView2dSession> sSurroundView2dSession GUARDED_BY(sLock);
-    static sp<SurroundView3dSession> sSurroundView3dSession GUARDED_BY(sLock);
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/VhalHandler.cpp b/cpp/surround_view/service-impl/VhalHandler.cpp
deleted file mode 100644
index 79ced83..0000000
--- a/cpp/surround_view/service-impl/VhalHandler.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "VhalHandler.h"
-
-#include <chrono>
-#include <cmath>
-#include <condition_variable>
-#include <mutex>
-
-#include <android-base/logging.h>
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include <time.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using vehicle::V2_0::IVehicle;
-using vehicle::V2_0::StatusCode;
-using vehicle::V2_0::VehiclePropertyType;
-using vehicle::V2_0::VehiclePropValue;
-
-bool VhalHandler::initialize(UpdateMethod updateMethod, int rate) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(mAccessLock);
-
-    if (mIsInitialized) {
-        LOG(ERROR) << "Vehicle Handler is already initialized.";
-        return false;
-    }
-
-    LOG(INFO) << "Connecting to Vehicle HAL";
-    mVhalServicePtr = IVehicle::getService();
-    if (mVhalServicePtr.get() == nullptr) {
-        LOG(ERROR) << "Vehicle HAL getService failed.";
-        return false;
-    }
-
-    if (rate < 1 || rate > 100) {
-        LOG(ERROR) << "Rate must be in the range [1, 100].";
-        return false;
-    }
-
-    if (mUpdateMethod == UpdateMethod::SUBSCRIBE) {
-        LOG(ERROR) << "Update method Subscribe is not currently implemented.";
-        return false;
-    }
-
-    mUpdateMethod = updateMethod;
-    mRate = rate;
-    mIsInitialized = true;
-    mIsUpdateActive = false;
-
-    return true;
-}
-
-void VhalHandler::pollProperties() {
-    LOG(DEBUG) << "Polling thread started.";
-    while (true) {
-        nsecs_t startTime = elapsedRealtimeNano();
-
-        // Copy properties to read.
-        std::vector<VehiclePropValue> propertiesToRead;
-        int rate;
-        {
-            std::scoped_lock<std::mutex> lock(mAccessLock);
-            if (!mIsUpdateActive) {
-                LOG(DEBUG) << "Exiting polling thread.";
-                break;
-            }
-            propertiesToRead = mPropertiesToRead;
-            rate = mRate;
-        }
-
-        // Make get call for each VHAL property.
-        // Write to back property values, note lock is not needed as only this thread uses it.
-        std::vector<VehiclePropValue> vehiclePropValuesUpdated;
-        for (auto& propertyToRead : propertiesToRead) {
-            StatusCode statusResult;
-            VehiclePropValue propValueResult;
-            mVhalServicePtr->get(propertyToRead,
-                                 [&statusResult,
-                                  &propValueResult](StatusCode status,
-                                                    const VehiclePropValue& propValue) {
-                                     statusResult = status;
-                                     propValueResult = propValue;
-                                 });
-            if (statusResult != StatusCode::OK) {
-                LOG(WARNING) << "Failed to read vhal property: " << propertyToRead.prop
-                             << ", with status code: " << static_cast<int32_t>(statusResult);
-            } else {
-                vehiclePropValuesUpdated.push_back(propValueResult);
-            }
-        }
-
-        // Update property values by swapping with updated property values.
-        {
-            std::scoped_lock<std::mutex> lock(mAccessLock);
-            std::swap(mPropertyValues, vehiclePropValuesUpdated);
-        }
-
-        std::unique_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
-        // Sleep to generate frames at kTargetFrameRate.
-        // rate is number of updates per seconds,
-        // Target time period between two updates in nano-seconds = (10 ^ 9) / rate.
-        const nsecs_t kTargetRateNs = std::pow(10, 9) / mRate;
-        const nsecs_t now = elapsedRealtimeNano();
-        const nsecs_t workTimeNs = now - startTime;
-        const nsecs_t sleepDurationNs = kTargetRateNs - workTimeNs;
-        if (sleepDurationNs > 0) {
-            // Sleep for sleepDurationNs or until a stop signal is received.
-            mPollThreadCondition.wait_for(sleepLock, std::chrono::nanoseconds(sleepDurationNs),
-                                          [this]() { return mPollStopSleeping; });
-        }
-    }
-}
-
-bool VhalHandler::startPropertiesUpdate() {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(mAccessLock);
-
-    // Check Vhal service is initialized.
-    if (!mIsInitialized) {
-        LOG(ERROR) << "VHAL handler not initialized.";
-        return false;
-    }
-
-    if (mIsUpdateActive) {
-        LOG(ERROR) << "Polling is already started.";
-        return false;
-    }
-
-    mIsUpdateActive = true;
-
-    {
-        std::scoped_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
-        mPollStopSleeping = false;
-    }
-
-    // Start polling thread if updated method is GET.
-    if (mUpdateMethod == UpdateMethod::GET) {
-        mPollingThread = std::thread([this]() { pollProperties(); });
-    }
-
-    return true;
-}
-
-bool VhalHandler::setPropertiesToRead(const std::vector<VehiclePropValue>& propertiesToRead) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(mAccessLock);
-
-    // Replace property ids to read.
-    mPropertiesToRead = propertiesToRead;
-
-    return true;
-}
-
-bool VhalHandler::setPropertiesToRead(const std::vector<uint64_t>& propertiesToRead) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::vector<VehiclePropValue> vhalPropValues;
-    for (const auto& property : propertiesToRead) {
-        VehiclePropValue propValue;
-        // Higher 32 bits = property id, lower 32 bits = area id.
-        propValue.areaId = property & 0xFFFFFFFF;
-        propValue.prop = (property >> 32) & 0xFFFFFFFF;
-        vhalPropValues.push_back(propValue);
-    }
-    return setPropertiesToRead(vhalPropValues);
-}
-
-bool VhalHandler::getPropertyValues(std::vector<VehiclePropValue>* property_values) {
-    LOG(DEBUG) << __FUNCTION__;
-    std::scoped_lock<std::mutex> lock(mAccessLock);
-
-    // Check Vhal service is initialized.
-    if (!mIsInitialized) {
-        LOG(ERROR) << "VHAL handler not initialized.";
-        return false;
-    }
-
-    // Copy current property values to argument.
-    *property_values = mPropertyValues;
-
-    return true;
-}
-
-bool VhalHandler::stopPropertiesUpdate() {
-    LOG(DEBUG) << __FUNCTION__;
-    {
-        std::scoped_lock<std::mutex> lock(mAccessLock);
-
-        // Check Vhal service is initialized.
-        if (!mIsInitialized) {
-            LOG(ERROR) << "VHAL handler not initialized.";
-            return false;
-        }
-
-        if (!mIsUpdateActive) {
-            LOG(ERROR) << "Polling is already stopped.";
-            return false;
-        }
-
-        mIsUpdateActive = false;
-    }
-
-    // Wake up the polling thread.
-    {
-        std::scoped_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
-        mPollStopSleeping = true;
-    }
-    mPollThreadCondition.notify_one();
-
-    // Wait for polling thread to exit.
-    mPollingThread.join();
-
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/VhalHandler.h b/cpp/surround_view/service-impl/VhalHandler.h
deleted file mode 100644
index 029e414..0000000
--- a/cpp/surround_view/service-impl/VhalHandler.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SURROUND_VIEW_SERVICE_IMPL_VHALHANDLER_H_
-#define SURROUND_VIEW_SERVICE_IMPL_VHALHANDLER_H_
-
-#include <mutex>
-#include <thread>
-#include <vector>
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-
-using android::sp;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// Vhal handler cache vhal properties needed and updates them at a fixed rate.
-class VhalHandler {
-public:
-    // Enumeration for the method to use for updating the VHAL properties,
-    enum UpdateMethod {
-        // Makes a periodic get call in a polling thread.
-        // Use when VHAL implementation does not support multiple clients in subscribe calls.
-        GET = 0,
-
-        // Subscribes to the VHAL properties, to receive values periodically in a callback.
-        // Use when VHAL implementation support multiple clients in subscribe calls.
-        // NOTE: Currently not implemented.
-        SUBSCRIBE
-    };
-
-    // Empty vhal handler constructor.
-    VhalHandler() : mIsInitialized(false), mUpdateMethod(GET), mRate(0), mIsUpdateActive(false) {}
-
-    // Initializes the VHAL handler.
-    // Valid range of rate is [1, 100] Hz.
-    // For subscribe the rate must be within each properties min and maximum sampling rate.
-    // For get, higher rate may result in excessive binder calls and increased latency.
-    bool initialize(UpdateMethod updateMethod, int rate);
-
-    // List of VHAL properties to read, can include vendor specific VHAL properties.
-    // The updated method determines if properties are updated using get or subscribe calls.
-    bool setPropertiesToRead(const std::vector<vehicle::V2_0::VehiclePropValue>& propertiesToRead);
-
-    // Convenience function to set vhal properties in a format returned from IO Module.
-    // uint64_t = (32 bits vhal property id) | (32 bits area id).
-    bool setPropertiesToRead(const std::vector<uint64_t>& propertiesToRead);
-
-    // Starts updating the VHAL properties with the specified rate.
-    bool startPropertiesUpdate();
-
-    // Gets the last updated VHAL property values.
-    // property_values is empty if startPropertiesUpdate() has not been called.
-    bool getPropertyValues(std::vector<vehicle::V2_0::VehiclePropValue>* property_values);
-
-    // Stops updating the VHAL properties.
-    // For Get method, waits for the polling thread to exit.
-    bool stopPropertiesUpdate();
-
-private:
-    // Thread function to poll properties.
-    void pollProperties();
-
-    // Pointer to VHAL service.
-    sp<vehicle::V2_0::IVehicle> mVhalServicePtr;
-
-    // Mutex for locking VHAL properties data.
-    std::mutex mAccessLock;
-
-    // Initialized parameters.
-    bool mIsInitialized;
-    UpdateMethod mUpdateMethod;
-    int mRate;
-    bool mIsUpdateActive;
-
-    // GET method related data members.
-    std::thread mPollingThread;
-    std::mutex mPollThreadSleepMutex;
-    std::condition_variable mPollThreadCondition;
-    bool mPollStopSleeping;
-
-    // List of properties to read.
-    std::vector<vehicle::V2_0::VehiclePropValue> mPropertiesToRead;
-
-    // Updated list of property values.
-    std::vector<vehicle::V2_0::VehiclePropValue> mPropertyValues;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // SURROUND_VIEW_SERVICE_IMPL_VHALHANDLER_H_
diff --git a/cpp/surround_view/service-impl/VhalHandlerTests.cpp b/cpp/surround_view/service-impl/VhalHandlerTests.cpp
deleted file mode 100644
index cd7c0e3..0000000
--- a/cpp/surround_view/service-impl/VhalHandlerTests.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define LOG_TAG "VhalHandlerTests"
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include "VhalHandler.h"
-
-#include <gtest/gtest.h>
-#include <time.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-namespace {
-
-using vehicle::V2_0::VehicleArea;
-using vehicle::V2_0::VehicleProperty;
-
-void SetSamplePropertiesToRead(VhalHandler* vhalHandler) {
-    std::vector<vehicle::V2_0::VehiclePropValue> propertiesToRead;
-    vehicle::V2_0::VehiclePropValue propertyRead;
-    propertyRead.prop = static_cast<int32_t>(VehicleProperty::INFO_MAKE);
-    propertiesToRead.push_back(propertyRead);
-    ASSERT_TRUE(vhalHandler->setPropertiesToRead(propertiesToRead));
-}
-
-void SetSamplePropertiesToReadInt64(VhalHandler* vhalHandler) {
-    std::vector<uint64_t> propertiesToRead;
-    uint64_t propertyInt64 = (static_cast<uint64_t>(VehicleProperty::INFO_MAKE) << 32) |
-            static_cast<uint64_t>(VehicleArea::GLOBAL);
-    propertiesToRead.push_back(propertyInt64);
-    ASSERT_TRUE(vhalHandler->setPropertiesToRead(propertiesToRead));
-}
-
-TEST(VhalhandlerTests, UninitializedStartFail) {
-    VhalHandler vhalHandler;
-    ASSERT_FALSE(vhalHandler.startPropertiesUpdate());
-}
-
-TEST(VhalhandlerTests, StartStopSuccess) {
-    VhalHandler vhalHandler;
-    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
-    SetSamplePropertiesToRead(&vhalHandler);
-    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
-    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
-}
-
-TEST(VhalhandlerTests, StopTwiceFail) {
-    VhalHandler vhalHandler;
-    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
-    SetSamplePropertiesToRead(&vhalHandler);
-    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
-    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
-    ASSERT_FALSE(vhalHandler.stopPropertiesUpdate());
-}
-
-TEST(VhalhandlerTests, NoStartFail) {
-    VhalHandler vhalHandler;
-    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
-    SetSamplePropertiesToRead(&vhalHandler);
-    ASSERT_FALSE(vhalHandler.stopPropertiesUpdate());
-}
-
-TEST(VhalhandlerTests, StartAgainSuccess) {
-    VhalHandler vhalHandler;
-    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
-    SetSamplePropertiesToRead(&vhalHandler);
-    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
-    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
-    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
-    ASSERT_TRUE(vhalHandler.stopPropertiesUpdate());
-}
-
-TEST(VhalhandlerTests, GetMethodSuccess) {
-    VhalHandler vhalHandler;
-    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
-
-    SetSamplePropertiesToRead(&vhalHandler);
-
-    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
-    sleep(1);
-    std::vector<vehicle::V2_0::VehiclePropValue> propertyValues;
-    EXPECT_TRUE(vhalHandler.getPropertyValues(&propertyValues));
-    EXPECT_EQ(propertyValues.size(), 1);
-
-    EXPECT_TRUE(vhalHandler.stopPropertiesUpdate());
-}
-
-TEST(VhalhandlerTests, GetMethodInt64Success) {
-    VhalHandler vhalHandler;
-    ASSERT_TRUE(vhalHandler.initialize(VhalHandler::UpdateMethod::GET, 10));
-
-    SetSamplePropertiesToReadInt64(&vhalHandler);
-
-    ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
-    sleep(1);
-    std::vector<vehicle::V2_0::VehiclePropValue> propertyValues;
-    EXPECT_TRUE(vhalHandler.getPropertyValues(&propertyValues));
-    EXPECT_EQ(propertyValues.size(), 1);
-
-    EXPECT_TRUE(vhalHandler.stopPropertiesUpdate());
-}
-
-}  // namespace
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc b/cpp/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc
deleted file mode 100644
index 4207e8f..0000000
--- a/cpp/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-service sv_service_impl /vendor/bin/android.automotive.sv.service@1.0-impl
-    class hal
-    user automotive_evs
-    group automotive_evs
-    disabled
diff --git a/cpp/surround_view/service-impl/core_lib.h b/cpp/surround_view/service-impl/core_lib.h
deleted file mode 100644
index 0265ca8..0000000
--- a/cpp/surround_view/service-impl/core_lib.h
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
-#define WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
-
-#include <array>
-#include <cstdint>
-#include <map>
-#include <string>
-#include <vector>
-
-namespace android_auto {
-namespace surround_view {
-
-// bounding box (bb)
-// It is used to describe the car model bounding box in 3D.
-// It assumes z = 0 and only x, y are used in the struct.
-// Of course, it is compatible to the 2d version bounding box and may be used
-// for other bounding box purpose (e.g., 2d bounding box in image).
-struct BoundingBox {
-    // (x,y) is bounding box's top left corner coordinate.
-    float x;
-    float y;
-
-    // (width, height) is the size of the bounding box.
-    float width;
-    float height;
-
-    BoundingBox() : x(0.0f), y(0.0f), width(0.0f), height(0.0f) {}
-
-    BoundingBox(float x_, float y_, float width_, float height_) :
-          x(x_), y(y_), width(width_), height(height_) {}
-
-    BoundingBox(const BoundingBox& bb_) :
-          x(bb_.x), y(bb_.y), width(bb_.width), height(bb_.height) {}
-
-    // Checks if data is valid.
-    bool IsValid() const { return width >= 0 && height >= 0; }
-
-    bool operator==(const BoundingBox& rhs) const {
-        return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
-    }
-
-    BoundingBox& operator=(const BoundingBox& rhs) {
-        x = rhs.x;
-        y = rhs.y;
-        width = rhs.width;
-        height = rhs.height;
-        return *this;
-    }
-};
-
-template <typename T>
-struct Coordinate2dBase {
-    // x coordinate.
-    T x;
-
-    // y coordinate.
-    T y;
-
-    Coordinate2dBase() : x(0), y(0) {}
-
-    Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
-
-    bool operator==(const Coordinate2dBase& rhs) const { return x == rhs.x && y == rhs.y; }
-
-    Coordinate2dBase& operator=(const Coordinate2dBase& rhs) {
-        x = rhs.x;
-        y = rhs.y;
-        return *this;
-    }
-};
-
-// integer type size.
-typedef Coordinate2dBase<int> Coordinate2dInteger;
-
-// float type size.
-typedef Coordinate2dBase<float> Coordinate2dFloat;
-
-struct Coordinate3dFloat {
-    // x coordinate.
-    float x;
-
-    // y coordinate.
-    float y;
-
-    // z coordinate.
-    float z;
-
-    Coordinate3dFloat() : x(0), y(0), z(0) {}
-
-    Coordinate3dFloat(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
-
-    bool operator==(const Coordinate3dFloat& rhs) const { return x == rhs.x && y == rhs.y; }
-
-    Coordinate3dFloat& operator=(const Coordinate3dFloat& rhs) {
-        x = rhs.x;
-        y = rhs.y;
-        return *this;
-    }
-};
-
-//  pixel weight used for illumination assessment
-struct PixelWeight {
-    // x and y are the coordinates (absolute value) in image space.
-    // pixel coordinate x in horizontal direction.
-    float x;
-
-    // pixel coordinate y in vertical direction.
-    float y;
-
-    // pixel weight, range in [0, 1].
-    float weight;
-
-    PixelWeight() : x(-1), y(-1), weight(0) {}
-
-    PixelWeight(int x_, int y_, int weight_) : x(x_), y(y_), weight(weight_) {}
-
-    bool operator==(const PixelWeight& rhs) const {
-        return x == rhs.x && y == rhs.y && weight == rhs.weight;
-    }
-
-    PixelWeight& operator=(const PixelWeight& rhs) {
-        x = rhs.x;
-        y = rhs.y;
-        weight = rhs.weight;
-        return *this;
-    }
-};
-
-// base size 2d type template.
-template <typename T>
-struct Size2dBase {
-    // width of size.
-    T width;
-
-    // height of size.
-    T height;
-
-    Size2dBase() : width(0), height(0) {}
-
-    Size2dBase(T width_, T height_) : width(width_), height(height_) {}
-
-    bool IsValid() const { return width > 0 && height > 0; }
-
-    bool operator==(const Size2dBase& rhs) const {
-        return width == rhs.width && height == rhs.height;
-    }
-
-    Size2dBase& operator=(const Size2dBase& rhs) {
-        width = rhs.width;
-        height = rhs.height;
-        return *this;
-    }
-};
-
-// integer type size.
-typedef Size2dBase<int> Size2dInteger;
-
-// float type size.
-typedef Size2dBase<float> Size2dFloat;
-
-//  surround view 2d parameters
-struct SurroundView2dParams {
-    // surround view 2d image resolution (width, height).
-    Size2dInteger resolution;
-
-    // the physical size of surround view 2d area in surround view coordinate.
-    // (surround view coordinate is defined as X rightward, Y forward and
-    // the origin lies on the center of the (symmetric) bowl (ground).
-    // When bowl is not used, surround view coordinate origin lies on the
-    // center of car model bounding box.)
-    // The unit should be consistent with camera extrinsics (translation).
-    Size2dFloat physical_size;
-
-    // the center of surround view 2d area in surround view coordinate
-    // (consistent with extrinsics coordinate).
-    Coordinate2dFloat physical_center;
-
-    // Enumeration for list of 2d blending types.
-    enum BlendingType { MULTIBAND = 0, ALPHA };
-
-    // Blending type for high quality preset.
-    BlendingType high_quality_blending;
-
-    // Blending type for low quality preset.
-    BlendingType low_quality_blending;
-
-    // whether gpu acceleration is enabled or not
-    bool gpu_acceleration_enabled;
-
-    SurroundView2dParams() :
-          resolution{0, 0},
-          physical_size{0.0f, 0.0f},
-          physical_center{0.0f, 0.0f},
-          high_quality_blending(BlendingType::MULTIBAND),
-          low_quality_blending(BlendingType::ALPHA),
-          gpu_acceleration_enabled(false) {}
-
-    SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
-                         Coordinate2dFloat physical_center_,
-                         bool gpu_acceleration_enabled_ = false) :
-          resolution(resolution_),
-          physical_size(physical_size_),
-          physical_center(physical_center_),
-          high_quality_blending(BlendingType::MULTIBAND),
-          low_quality_blending(BlendingType::ALPHA),
-          gpu_acceleration_enabled(gpu_acceleration_enabled_) {}
-
-    // Checks if data is valid.
-    bool IsValid() const { return resolution.IsValid() && physical_size.IsValid(); }
-
-    bool operator==(const SurroundView2dParams& rhs) const {
-        return resolution == rhs.resolution && physical_size == rhs.physical_size &&
-                physical_center == rhs.physical_center &&
-                high_quality_blending == rhs.high_quality_blending &&
-                low_quality_blending == rhs.low_quality_blending &&
-                gpu_acceleration_enabled == rhs.gpu_acceleration_enabled;
-    }
-
-    SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
-        resolution = rhs.resolution;
-        physical_size = rhs.physical_size;
-        physical_center = rhs.physical_center;
-        high_quality_blending = rhs.high_quality_blending;
-        low_quality_blending = rhs.low_quality_blending;
-        gpu_acceleration_enabled = rhs.gpu_acceleration_enabled;
-        return *this;
-    }
-};
-
-//  surround view 3d parameters
-struct SurroundView3dParams {
-    // Bowl center is the origin of the surround view coordinate. If surround view
-    // coordinate is different from the global one, a coordinate system
-    // transformation function is required.
-
-    // planar area radius.
-    // Range in (0, +Inf).
-    float plane_radius;
-
-    // the number of divisions on the plane area of bowl, in the direction
-    // of the radius.
-    // Range in [1, +Inf).
-    int plane_divisions;
-
-    // bowl curve curve height.
-    // Range in (0, +Inf).
-    float curve_height;
-
-    // the number of points on bowl curve curve along radius direction.
-    // Range in [1, +Inf).
-    int curve_divisions;
-
-    // the number of points along circle (360 degrees)
-    // Range in [1, +Inf).
-    int angular_divisions;
-
-    // the parabola coefficient of bowl curve curve.
-    // The curve formula is z = a * (x^2 + y^2) for sqrt(x^2 + y^2) >
-    // plane_radius; a is curve_coefficient.
-    // Range in (0, +Inf).
-    float curve_coefficient;
-
-    // render output image size.
-    Size2dInteger resolution;
-
-    // Include shadows in high details preset.
-    bool high_details_shadows;
-
-    // Include reflections in high details preset.
-    bool high_details_reflections;
-
-    SurroundView3dParams() :
-          plane_radius(0.0f),
-          plane_divisions(0),
-          curve_height(0.0f),
-          curve_divisions(0),
-          angular_divisions(0),
-          curve_coefficient(0.0f),
-          resolution(0, 0),
-          high_details_shadows(true),
-          high_details_reflections(true) {}
-
-    SurroundView3dParams(float plane_radius_, int plane_divisions_, float curve_height_,
-                         int curve_divisions_, int angular_divisions_, float curve_coefficient_,
-                         Size2dInteger resolution_) :
-          plane_radius(plane_radius_),
-          plane_divisions(plane_divisions_),
-          curve_height(curve_height_),
-          curve_divisions(curve_divisions_),
-          angular_divisions(angular_divisions_),
-          curve_coefficient(curve_coefficient_),
-          resolution(resolution_),
-          high_details_shadows(true),
-          high_details_reflections(true) {}
-
-    // Checks if data is valid.
-    bool IsValid() const {
-        return plane_radius > 0 && plane_divisions > 0 && curve_height > 0 &&
-                angular_divisions > 0 && curve_coefficient > 0 && curve_divisions > 0 &&
-                resolution.IsValid();
-    }
-
-    bool operator==(const SurroundView3dParams& rhs) const {
-        return plane_radius == rhs.plane_radius && plane_divisions == rhs.plane_divisions &&
-                curve_height == rhs.curve_height && curve_divisions == rhs.curve_divisions &&
-                angular_divisions == rhs.angular_divisions &&
-                curve_coefficient == rhs.curve_coefficient && resolution == rhs.resolution &&
-                high_details_shadows == rhs.high_details_shadows &&
-                high_details_reflections == rhs.high_details_reflections;
-    }
-
-    SurroundView3dParams& operator=(const SurroundView3dParams& rhs) {
-        plane_radius = rhs.plane_radius;
-        plane_divisions = rhs.plane_divisions;
-        curve_height = rhs.curve_height;
-        curve_divisions = rhs.curve_divisions;
-        angular_divisions = rhs.angular_divisions;
-        curve_coefficient = rhs.curve_coefficient;
-        resolution = rhs.resolution;
-        high_details_shadows = rhs.high_details_shadows;
-        high_details_reflections = rhs.high_details_reflections;
-        return *this;
-    }
-};
-
-// surround view camera parameters with native types only.
-struct SurroundViewCameraParams {
-    // All calibration data |intrinsics|, |rvec| and |tvec|
-    // follow OpenCV format excepting using native arrays, refer:
-    // https://docs.opencv.org/3.4.0/db/d58/group__calib3d__fisheye.html
-    // camera intrinsics. It is the 1d array of camera matrix(3X3) with row first.
-    float intrinsics[9];
-
-    // lens distortion parameters.
-    float distorion[4];
-
-    // rotation vector.
-    float rvec[3];
-
-    // translation vector.
-    float tvec[3];
-
-    // camera image size (width, height).
-    Size2dInteger size;
-
-    // fisheye circular fov.
-    float circular_fov;
-
-    // Full path and filename to the validity mask image file.
-    // Mask specifies the valid region of pixels within input camera image.
-    std::string validity_mask_filename;
-
-    bool operator==(const SurroundViewCameraParams& rhs) const {
-        return (0 == std::memcmp(intrinsics, rhs.intrinsics, 9 * sizeof(float))) &&
-                (0 == std::memcmp(distorion, rhs.distorion, 4 * sizeof(float))) &&
-                (0 == std::memcmp(rvec, rhs.rvec, 3 * sizeof(float))) &&
-                (0 == std::memcmp(tvec, rhs.tvec, 3 * sizeof(float))) && size == rhs.size &&
-                circular_fov == rhs.circular_fov;
-    }
-
-    SurroundViewCameraParams& operator=(const SurroundViewCameraParams& rhs) {
-        std::memcpy(intrinsics, rhs.intrinsics, 9 * sizeof(float));
-        std::memcpy(distorion, rhs.distorion, 4 * sizeof(float));
-        std::memcpy(rvec, rhs.rvec, 3 * sizeof(float));
-        std::memcpy(tvec, rhs.tvec, 3 * sizeof(float));
-        size = rhs.size;
-        circular_fov = rhs.circular_fov;
-        return *this;
-    }
-};
-
-// 3D vertex of an overlay object.
-struct OverlayVertex {
-    // Position in 3d coordinates in world space in order X,Y,Z.
-    float pos[3];
-    // RGBA values, A is used for transparency.
-    uint8_t rgba[4];
-
-    bool operator==(const OverlayVertex& rhs) const {
-        return (0 == std::memcmp(pos, rhs.pos, 3 * sizeof(float))) &&
-                (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t)));
-    }
-
-    OverlayVertex& operator=(const OverlayVertex& rhs) {
-        std::memcpy(pos, rhs.pos, 3 * sizeof(float));
-        std::memcpy(rgba, rhs.rgba, 4 * sizeof(uint8_t));
-        return *this;
-    }
-};
-
-// Overlay is a list of vertices (may be a single or multiple objects in scene)
-// coming from a single source or type of sensor.
-struct Overlay {
-    // Uniqiue Id identifying each overlay.
-    uint16_t id;
-
-    // List of overlay vertices. 3 consecutive vertices form a triangle.
-    std::vector<OverlayVertex> vertices;
-
-    // Constructor initializing all member.
-    Overlay(uint16_t id_, const std::vector<OverlayVertex>& vertices_) {
-        id = id_;
-        vertices = vertices_;
-    }
-
-    // Default constructor.
-    Overlay() {
-        id = 0;
-        vertices = std::vector<OverlayVertex>();
-    }
-};
-
-// -----------   Structs related to car model  ---------------
-
-// 3D Vertex of a car model with normal and optionally texture coordinates.
-struct CarVertex {
-    // 3d position in (x, y, z).
-    std::array<float, 3> pos;
-
-    // unit normal at vertex, used for diffuse shading.
-    std::array<float, 3> normal;
-
-    // texture coordinates, valid in range [0, 1]. (-1, -1) implies no
-    // texture sampling. Note: only a single texture coordinate is currently
-    // supported per vertex. This struct will need to be extended with another
-    // tex_coord if multiple textures are needed per vertex.
-    std::array<float, 2> tex_coord;
-
-    // Default constructor.
-    CarVertex() {
-        pos = {0, 0, 0};
-        normal = {1, 0, 0};
-        tex_coord = {-1.0f, -1.0f};
-    }
-
-    CarVertex(const std::array<float, 3>& _pos, const std::array<float, 3>& _normal,
-              const std::array<float, 2> _tex_coord) :
-          pos(_pos), normal(_normal), tex_coord(_tex_coord) {}
-};
-
-// Type of texture (color, bump, procedural etc.)
-// Currently only color is supported.
-enum CarTextureType : uint32_t {
-    // Texture map is applied to all color parameters: Ka, Kd and Ks.
-    // Data type of texture is RGB with each channel a uint8_t.
-    kKa = 0,
-    kKd,
-    kKs,
-
-    // Texture for bump maps. Data type is 3 channel float.
-    kBumpMap
-};
-
-// Textures to be used for rendering car model.
-struct CarTexture {
-    // Type and number of channels are dependant on each car texture type.
-    int width;
-    int height;
-    int channels;
-    int bytes_per_channel;
-    uint8_t* data;
-
-    CarTexture() {
-        width = 0;
-        height = 0;
-        channels = 0;
-        bytes_per_channel = 0;
-        data = nullptr;
-    }
-};
-
-// Material parameters for a car part.
-// Refer to MTL properties: http://paulbourke.net/dataformats/mtl/
-struct CarMaterial {
-    // Illumination model - 0, 1, 2 currently supported
-    // 0 = Color on and Ambient off
-    // 1 = Color on and Ambient on
-    // 2 = Highlight on
-    // 3 = Reflection on and Ray trace on
-    // 4 - 10 = Reflection/Transparency options not supported,
-    //          Will default to option 3.
-    uint8_t illum;
-
-    std::array<float, 3> ka;  // Ambient RGB [0, 1]
-    std::array<float, 3> kd;  // Diffuse RGB [0, 1]
-    std::array<float, 3> ks;  // Specular RGB [0, 1]
-
-    // Dissolve factor [0, 1], 0 = full transparent, 1 = full opaque.
-    float d;
-
-    // Specular exponent typically range from 0 to 1000.
-    // A high exponent results in a tight, concentrated highlight.
-    float ns;
-
-    // Set default values of material.
-    CarMaterial() {
-        illum = 0;                // Color on, ambient off
-        ka = {0.0f, 0.0f, 0.0f};  // No ambient.
-        kd = {0.0f, 0.0f, 0.0f};  // No dissolve.
-        ks = {0.0f, 0.0f, 0.0f};  // No specular.
-        d = 1.0f;                 // Fully opaque.
-        ns = 0;                   // No specular exponent.
-    }
-
-    // Map for texture type to a string id of a texture.
-    std::map<CarTextureType, std::string> textures;
-};
-
-// Type alias for 4x4 homogenous matrix, in row-major order.
-using Mat4x4 = std::array<float, 16>;
-
-// Represents a part of a car model.
-// Each car part is a object in the car that is individually animated and
-// has the same illumination properties. A car part may contain sub parts.
-struct CarPart {
-    // Car part vertices.
-    std::vector<CarVertex> vertices;
-
-    // Properties/attributes describing car material.
-    CarMaterial material;
-
-    // Model matrix to transform the car part from object space to its parent's
-    // coordinate space.
-    // The car's vertices are transformed by performing:
-    // parent_model_mat * model_mat * car_part_vertices to transform them to the
-    // global coordinate space.
-    // Model matrix must be a homogenous matrix with orthogonal rotation matrix.
-    Mat4x4 model_mat;
-
-    // Id of parent part. Parent part's model matrix is used to animate this part.
-    // empty string implies the part has no parent.
-    std::string parent_part_id;
-
-    // Ids of child parts. If current part is animated all its child parts
-    // are animated as well. Empty vector implies part has not children.
-    std::vector<std::string> child_part_ids;
-
-    CarPart(const std::vector<CarVertex>& car_vertices, const CarMaterial& car_material,
-            const Mat4x4& car_model_mat, std::string car_parent_part_id,
-            const std::vector<std::string>& car_child_part_ids) :
-          vertices(car_vertices),
-          material(car_material),
-          model_mat(car_model_mat),
-          parent_part_id(car_parent_part_id),
-          child_part_ids(car_child_part_ids) {}
-
-    CarPart& operator=(const CarPart& car_part) {
-        this->vertices = car_part.vertices;
-        this->material = car_part.material;
-        this->model_mat = car_part.model_mat;
-        this->parent_part_id = car_part.parent_part_id;
-        this->child_part_ids = car_part.child_part_ids;
-        return *this;
-    }
-};
-
-struct AnimationParam {
-    // part id
-    std::string part_id;
-
-    // model matrix.
-    Mat4x4 model_matrix;
-
-    // bool flag indicating if the model matrix is updated from last
-    // SetAnimations() call.
-    bool is_model_update;
-
-    // gamma.
-    float gamma;
-
-    // bool flag indicating if gamma is updated from last
-    // SetAnimations() call.
-    bool is_gamma_update;
-
-    // texture id.
-    std::string texture_id;
-
-    // bool flag indicating if texture is updated from last
-    // SetAnimations() call.
-    bool is_texture_update;
-
-    // Default constructor, no animations are updated.
-    AnimationParam() {
-        is_model_update = false;
-        is_gamma_update = false;
-        is_texture_update = false;
-    }
-
-    // Constructor with car part name.
-    explicit AnimationParam(const std::string& _part_id) :
-          part_id(_part_id),
-          is_model_update(false),
-          is_gamma_update(false),
-          is_texture_update(false) {}
-
-    void SetModelMatrix(const Mat4x4& model_mat) {
-        is_model_update = true;
-        model_matrix = model_mat;
-    }
-
-    void SetGamma(float gamma_value) {
-        is_gamma_update = true;
-        gamma = gamma_value;
-    }
-
-    void SetTexture(const std::string& tex_id) {
-        is_texture_update = true;
-        texture_id = tex_id;
-    }
-};
-
-enum Format {
-    GRAY = 0,
-    RGB = 1,
-    RGBA = 2,
-};
-
-// collection of surround view static data params.
-struct SurroundViewStaticDataParams {
-    std::vector<SurroundViewCameraParams> cameras_params;
-
-    // surround view 2d parameters.
-    SurroundView2dParams surround_view_2d_params;
-
-    // surround view 3d parameters.
-    SurroundView3dParams surround_view_3d_params;
-
-    // undistortion focal length scales.
-    std::vector<float> undistortion_focal_length_scales;
-
-    // car model bounding box for 2d surround view.
-    BoundingBox car_model_bb;
-
-    // map of texture name to a car texture. Lists all textures to be
-    // used for car model rendering.
-    std::map<std::string, CarTexture> car_textures;
-
-    // map of car id to a car part. Lists all car parts to be used
-    // for car model rendering.
-    std::map<std::string, CarPart> car_parts;
-
-    SurroundViewStaticDataParams(const std::vector<SurroundViewCameraParams>& sv_cameras_params,
-                                 const SurroundView2dParams& sv_2d_params,
-                                 const SurroundView3dParams& sv_3d_params,
-                                 const std::vector<float>& scales, const BoundingBox& bb,
-                                 const std::map<std::string, CarTexture>& textures,
-                                 const std::map<std::string, CarPart>& parts) :
-          cameras_params(sv_cameras_params),
-          surround_view_2d_params(sv_2d_params),
-          surround_view_3d_params(sv_3d_params),
-          undistortion_focal_length_scales(scales),
-          car_model_bb(bb),
-          car_textures(textures),
-          car_parts(parts) {}
-};
-
-// Constant used as an invalid memory id for SurroundViewInputBufferPointers and
-// SurroundViewResultPointer. Setting to `memory_id` to kInvalidMemoryId implies
-// no caching is performed.
-const uint64_t kInvalidMemoryId = UINT64_MAX;
-
-// Currently we keep both cpu and gpu data pointers, and only one of them should
-// be valid at a certain point. Also, users are responsible to allocate and
-// de-allocate the pointers.
-// TODO(b/174778117): consider use only one data pointer once GPU migration is
-// done.
-// TODO(b/184870125): Consider merging with SurroundViewInputBufferPointers.
-struct SurroundViewInputBufferPointers {
-    void* gpu_data_pointer;
-    void* cpu_data_pointer;
-    Format format;
-    int width;
-    int height;
-    // Unique identifier for the CPU/GPU data buffer. If memory id is the same as
-    // a previously provided input buffer, cached intermediate allocated data will
-    // be used for faster operation. If `memory_id` is kInvalidMemoryId no caching
-    // is performed. Currently supported: SV2D GPU pipeline with
-    // `gpu_data_pointer`.
-    // Recommend the `memory_id` provided by client to be created as:
-    // ((camera_index) << 32 )  | (graphics_buffer_id).
-    uint64_t memory_id;
-    SurroundViewInputBufferPointers() :
-          gpu_data_pointer(nullptr),
-          cpu_data_pointer(nullptr),
-          width(0),
-          height(0),
-          memory_id(kInvalidMemoryId) {}
-    SurroundViewInputBufferPointers(void* gpu_data_pointer_, void* cpu_data_pointer_,
-                                    Format format_, int width_, int height_,
-                                    uint64_t memory_id_ = kInvalidMemoryId) :
-          gpu_data_pointer(gpu_data_pointer_),
-          cpu_data_pointer(cpu_data_pointer_),
-          format(format_),
-          width(width_),
-          height(height_),
-          memory_id(memory_id_) {}
-};
-
-// Currently we keep both cpu and gpu data pointers, and only one of them should
-// be valid at a certain point. Users need to check null before they make use of
-// the data pointers.
-// TODO(b/174778117): consider use only one data pointer once GPU migration is
-// done.
-// TODO(b/184870125): Consider merging with SurroundViewInputBufferPointers.
-struct SurroundViewResultPointer {
-    void* gpu_data_pointer;
-    void* cpu_data_pointer;
-    Format format;
-    int width;
-    int height;
-    bool is_data_preallocated;
-    // Unique identifier for the CPU/GPU data buffer. If memory id is the same as
-    // a previously provided result buffer, cached intermediate allocated data
-    // will be used for faster operation. If memory_id is kInvalidMemoryId no
-    // caching is performed. Currently supported: SV2D GPU pipeline with
-    // 'gpu_data_pointer'.
-    // Recommend the `memory_id` provided by client to be created as:
-    // ((camera_index) << 32 )  | (graphics_buffer_id).
-    uint64_t memory_id;
-    SurroundViewResultPointer() :
-          gpu_data_pointer(nullptr),
-          cpu_data_pointer(nullptr),
-          width(0),
-          height(0),
-          is_data_preallocated(false),
-          memory_id(kInvalidMemoryId) {}
-
-    // Constructor with result cpu data pointer being allocated within core lib.
-    // Use for cases when no already existing buffer is available.
-    SurroundViewResultPointer(Format format_, int width_, int height_) :
-          format(format_), width(width_), height(height_) {
-        // default formate is gray.
-        const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
-        cpu_data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
-        gpu_data_pointer = nullptr;
-        is_data_preallocated = false;
-        memory_id = kInvalidMemoryId;
-    }
-
-    // Constructor with pre-allocated data.
-    // Use for cases when results must be added to an existing allocated buffer.
-    // Example, pre-allocated buffer of a display.
-    SurroundViewResultPointer(void* gpu_data_pointer_, void* cpu_data_pointer_, Format format_,
-                              int width_, int height_) :
-          gpu_data_pointer(gpu_data_pointer_),
-          cpu_data_pointer(cpu_data_pointer_),
-          format(format_),
-          width(width_),
-          height(height_),
-          is_data_preallocated(true),
-          memory_id(kInvalidMemoryId) {}
-
-    ~SurroundViewResultPointer() {
-        if (cpu_data_pointer) {
-            if (!is_data_preallocated) {
-                delete[] static_cast<char*>(cpu_data_pointer);
-            }
-            cpu_data_pointer = nullptr;
-        }
-    }
-};
-
-// External renderer configuration for SV3D.
-struct RendererInfo {
-  // Enumeration for the rendering API to be used.
-  enum RenderingApi { OPENGLES, VULKAN };
-
-  // Rendering API used external renderer.
-  // OpenGLES is supported as an external renderer.
-  // Vulkan is currently not supported as an external renderer.
-  RenderingApi api;
-
-  // OpenGLES version >= 3.1 is supported.
-  int version_major;
-  int version_minor;
-};
-
-// Initialization info for external OpenGLES rendering.
-struct OpenGlInitInfo {
-  // Type EGLDisplay
-  void* egl_display;
-
-  // Type EGLSurface
-  void* egl_surface;
-
-  // Type EGLContext
-  void* egl_context;
-};
-
-class SurroundView {
-public:
-    virtual ~SurroundView() = default;
-
-    // Sets SurroundView static data.
-    // For details of SurroundViewStaticDataParams, please refer to the
-    // definition.
-    virtual bool SetStaticData(const SurroundViewStaticDataParams& static_data_params) = 0;
-
-    // Starts 2d pipeline. Returns false if error occurs.
-    virtual bool Start2dPipeline() = 0;
-
-    // Starts 3d pipeline. Returns false if error occurs.
-    virtual bool Start3dPipeline() = 0;
-
-    // Starts Surround View 3D pipeline to render into an external OpenGLES scene.
-    // `external_renderer_info` - contains data structs specifying the external
-    // renderer initialization information.
-    // `opengl_init_info` - contains the OpenGLES structs required for
-    // initialization. Returns false if error occurs.
-    virtual bool Start3dPipelineExternal(const RendererInfo& external_renderer_info,
-                                         const OpenGlInitInfo& opengl_init_info) = 0;
-
-    // Stops 2d pipleline. It releases resource owned by the pipeline.
-    // Returns false if error occurs.
-    virtual void Stop2dPipeline() = 0;
-
-    // Stops 3d pipeline. It releases resource owned by the pipeline.
-    virtual void Stop3dPipeline() = 0;
-
-    // Updates 2d output resolution on-the-fly. Starts2dPipeline() must be called
-    // before this can be called. For quality assurance, the |resolution| should
-    // not be larger than the original one. This call is not thread safe and there
-    // is no sync between Get2dSurroundView() and this call.
-    virtual bool Update2dOutputResolution(const Size2dInteger& resolution) = 0;
-
-    // Updates 3d output resolution on-the-fly. Starts3dPipeline() must be called
-    // before this can be called. For quality assurance, the |resolution| should
-    // not be larger than the original one. This call is not thread safe and there
-    // is no sync between Get3dSurroundView() and this call.
-    virtual bool Update3dOutputResolution(const Size2dInteger& resolution) = 0;
-
-    // Projects camera's pixel location to surround view 2d image location.
-    // |camera_point| is the pixel location in raw camera's space.
-    // |camera_index| is the camera's index.
-    // |surround_view_2d_point| is the surround view 2d image pixel location.
-    virtual bool GetProjectionPointFromRawCameraToSurroundView2d(
-            const Coordinate2dInteger& camera_point, int camera_index,
-            Coordinate2dFloat* surround_view_2d_point) = 0;
-
-    // Projects camera's pixel location to surround view 3d bowl coordinate.
-    // |camera_point| is the pixel location in raw camera's space.
-    // |camera_index| is the camera's index.
-    // |surround_view_3d_point| is the surround view 3d vertex.
-    virtual bool GetProjectionPointFromRawCameraToSurroundView3d(
-            const Coordinate2dInteger& camera_point, int camera_index,
-            Coordinate3dFloat* surround_view_3d_point) = 0;
-
-    // Gets 2d surround view image.
-    // It takes input_pointers as input, and output is result_pointer.
-    // Please refer to the definition of SurroundViewInputBufferPointers and
-    // SurroundViewResultPointer.
-    virtual bool Get2dSurroundView(
-            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-            SurroundViewResultPointer* result_pointer) = 0;
-
-    // Gets 3d surround view image.
-    // It takes |input_pointers| and |view_matrix| as input, and output is
-    // |result_pointer|. |view_matrix| is 4 x 4 matrix.
-    // Please refer to the definition of
-    // SurroundViewInputBufferPointers and
-    // SurroundViewResultPointer.
-    virtual bool Get3dSurroundView(
-            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-            const std::array<std::array<float, 4>, 4>& view_matrix,
-            SurroundViewResultPointer* result_pointer) = 0;
-
-    // Gets 3d surround view image overload.
-    // It takes |input_pointers|, |quaternion| and |translation| as input,
-    // and output is |result_pointer|.
-    // |quaternion| is 4 x 1 array (X, Y, Z, W).
-    // It is required to be unit quaternion as rotation quaternion.
-    // |translation| is 3 X 1 array (x, y, z).
-    // Please refer to the definition of
-    // SurroundViewInputBufferPointers and
-    // SurroundViewResultPointer.
-    virtual bool Get3dSurroundView(
-            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-            const std::array<float, 4>& quaternion, const std::array<float, 3>& translation,
-            SurroundViewResultPointer* result_pointer) = 0;
-
-    // Updates the Surround View 3D Bowl in an external renderer scene with the
-    // images provided by `input_pointers` and view in `view_matrix`.
-    // Call is only valid if pipeline is started with Start3dPipelineExternal().
-    virtual bool Update3dSurroundViewExternal(
-            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-            const std::array<std::array<float, 4>, 4>& view_matrix) = 0;
-
-    // Sets 3d overlays.
-    virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 0;
-
-    // Animates a set of car parts.
-    // Only updated car parts are included.
-    // |car_animations| is a vector of AnimationParam specifying updated
-    // car parts with updated animation parameters.
-    virtual bool SetAnimations(const std::vector<AnimationParam>& car_animations) = 0;
-
-    // for test only.
-    virtual std::vector<SurroundViewInputBufferPointers> ReadImages(const char* filename0,
-                                                                    const char* filename1,
-                                                                    const char* filename2,
-                                                                    const char* filename3) = 0;
-
-    virtual void WriteImage(const SurroundViewResultPointer result_pointerer,
-                            const char* filename) = 0;
-};
-
-SurroundView* Create();
-
-}  // namespace surround_view
-}  // namespace android_auto
-
-#endif  // WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
diff --git a/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
deleted file mode 100755
index 6c4927b..0000000
--- a/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so b/cpp/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
deleted file mode 100755
index d718426..0000000
--- a/cpp/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/lib/x86/libcore_lib_shared.so b/cpp/surround_view/service-impl/lib/x86/libcore_lib_shared.so
deleted file mode 100755
index dd4eb11..0000000
--- a/cpp/surround_view/service-impl/lib/x86/libcore_lib_shared.so
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml b/cpp/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml
deleted file mode 100644
index f9e4548..0000000
--- a/cpp/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright 2020 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.
--->
-<manifest version="1.0" type="device" >
-    <hal format="hidl">
-        <name>android.hardware.automotive.sv</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>ISurroundViewService</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp b/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
deleted file mode 100644
index 76ed76f..0000000
--- a/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "MockEvsCamera.h"
-
-#include <stdlib.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-// TODO(b/159733690): the number should come from xml
-const int kFramesCount = 4;
-const int kFrameGenerationDelayMillis = 30;
-
-// Evs Camera Id names defined in sv_sample_config.xml.
-const char kEvsCameraDeviceIdNames[4][20] = {
-    "/dev/video60", "/dev/video61", "/dev/video62", "/dev/video63"
-};
-
-
-MockEvsCamera::MockEvsCamera(const string& cameraId, const Stream& streamCfg) {
-    mConfigManager = ConfigManager::Create();
-
-    mStreamCfg.height = streamCfg.height;
-    mStreamCfg.width = streamCfg.width;
-
-    mCameraDesc.v1.cameraId = cameraId;
-    unique_ptr<ConfigManager::CameraGroupInfo>& cameraGroupInfo =
-            mConfigManager->getCameraGroupInfo(mCameraDesc.v1.cameraId);
-    if (cameraGroupInfo != nullptr) {
-        mCameraDesc.metadata.setToExternal(
-                (uint8_t*)cameraGroupInfo->characteristics,
-                get_camera_metadata_size(cameraGroupInfo->characteristics));
-    }
-}
-
-Return<void> MockEvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<EvsResult> MockEvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
-    // Not implemented.
-
-    (void)bufferCount;
-    return EvsResult::OK;
-}
-
-Return<EvsResult> MockEvsCamera::startVideoStream(
-        const ::android::sp<IEvsCameraStream_1_0>& stream) {
-    LOG(INFO) << __FUNCTION__;
-    scoped_lock<mutex> lock(mAccessLock);
-
-    mStream = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
-
-    if (mStreamState != STOPPED) {
-        LOG(ERROR) << "Ignoring startVideoStream call when a stream is "
-                   << "already running.";
-        return EvsResult::STREAM_ALREADY_RUNNING;
-    }
-
-    // Start the frame generation thread
-    mStreamState = RUNNING;
-    mCaptureThread = thread([this]() { generateFrames(); });
-
-    return EvsResult::OK;
-}
-
-Return<void> MockEvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
-    // Not implemented.
-
-    (void)buffer;
-    return {};
-}
-
-Return<void> MockEvsCamera::stopVideoStream() {
-    LOG(INFO) << __FUNCTION__;
-
-    unique_lock<mutex> lock(mAccessLock);
-    if (mStreamState == RUNNING) {
-        // Tell the GenerateFrames loop we want it to stop
-        mStreamState = STOPPING;
-        // Block outside the mutex until the "stop" flag has been acknowledged
-        // We won't send any more frames, but the client might still get some
-        // already in flight
-        LOG(DEBUG) << __FUNCTION__ << ": Waiting for stream thread to end...";
-        lock.unlock();
-        mCaptureThread.join();
-        lock.lock();
-        mStreamState = STOPPED;
-        mStream = nullptr;
-        LOG(DEBUG) << "Stream marked STOPPED.";
-    }
-    return {};
-}
-
-Return<int32_t> MockEvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
-    // Not implemented.
-
-    (void)opaqueIdentifier;
-    return 0;
-}
-
-Return<EvsResult> MockEvsCamera::setExtendedInfo(uint32_t opaqueIdentifier,
-                                                 int32_t opaqueValue) {
-    // Not implemented.
-
-    (void)opaqueIdentifier;
-    (void)opaqueValue;
-    return EvsResult::OK;
-}
-
-Return<void> MockEvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
-    _hidl_cb(mCameraDesc);
-    return {};
-}
-
-Return<void> MockEvsCamera::getPhysicalCameraInfo(
-        const hidl_string& deviceId, getPhysicalCameraInfo_cb _hidl_cb) {
-    CameraDesc_1_1 desc = {};
-    desc.v1.cameraId = deviceId;
-
-    unique_ptr<ConfigManager::CameraInfo>& cameraInfo =
-            mConfigManager->getCameraInfo(deviceId);
-    if (cameraInfo != nullptr) {
-        desc.metadata.setToExternal(
-                (uint8_t*)cameraInfo->characteristics,
-                get_camera_metadata_size(cameraInfo->characteristics));
-    }
-
-    _hidl_cb(desc);
-
-    return {};
-}
-
-Return<EvsResult> MockEvsCamera::doneWithFrame_1_1(
-        const hardware::hidl_vec<BufferDesc_1_1>& buffer) {
-    // Not implemented.
-
-    (void)buffer;
-    return EvsResult::OK;
-}
-
-Return<EvsResult> MockEvsCamera::setMaster() {
-    // Not implemented.
-
-    return EvsResult::OK;
-}
-
-Return<EvsResult> MockEvsCamera::forceMaster(
-        const sp<IEvsDisplay_1_0>& display) {
-    // Not implemented.
-
-    (void)display;
-    return EvsResult::OK;
-}
-
-Return<EvsResult> MockEvsCamera::unsetMaster() {
-    // Not implemented.
-
-    return EvsResult::OK;
-}
-
-Return<void> MockEvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<void> MockEvsCamera::getIntParameterRange(
-        CameraParam id, getIntParameterRange_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)id;
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<void> MockEvsCamera::setIntParameter(CameraParam id, int32_t value,
-                                            setIntParameter_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)id;
-    (void)value;
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<void> MockEvsCamera::getIntParameter(
-        CameraParam id, getIntParameter_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)id;
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<EvsResult> MockEvsCamera::setExtendedInfo_1_1(
-    uint32_t opaqueIdentifier, const hidl_vec<uint8_t>& opaqueValue) {
-    // Not implemented.
-
-    (void)opaqueIdentifier;
-    (void)opaqueValue;
-    return EvsResult::OK;
-}
-
-Return<void> MockEvsCamera::getExtendedInfo_1_1(
-        uint32_t opaqueIdentifier, getExtendedInfo_1_1_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)opaqueIdentifier;
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<void> MockEvsCamera::importExternalBuffers(
-        const hidl_vec<BufferDesc_1_1>& buffers,
-        importExternalBuffers_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)buffers;
-    (void)_hidl_cb;
-    return {};
-}
-
-void MockEvsCamera::initializeFrames(int framesCount) {
-    LOG(INFO) << "StreamCfg width: " << mStreamCfg.width
-              << " height: " << mStreamCfg.height;
-
-    string label = "EmptyBuffer_";
-    mGraphicBuffers.resize(framesCount);
-    mBufferDescs.resize(framesCount);
-    for (int i = 0; i < framesCount; i++) {
-        mGraphicBuffers[i] = new GraphicBuffer(mStreamCfg.width,
-                                               mStreamCfg.height,
-                                               HAL_PIXEL_FORMAT_RGBA_8888,
-                                               1,
-                                               GRALLOC_USAGE_HW_TEXTURE,
-                                               label + (char)(i + 48));
-        mBufferDescs[i].buffer.nativeHandle =
-                mGraphicBuffers[i]->getNativeBuffer()->handle;
-        mBufferDescs[i].deviceId = kEvsCameraDeviceIdNames[i];
-        AHardwareBuffer_Desc* pDesc =
-                reinterpret_cast<AHardwareBuffer_Desc*>(
-                        &mBufferDescs[i].buffer.description);
-        pDesc->width = mStreamCfg.width;
-        pDesc->height = mStreamCfg.height;
-        pDesc->layers = 1;
-        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
-        pDesc->stride = mGraphicBuffers[i]->getStride();
-        pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
-    }
-}
-
-void MockEvsCamera::generateFrames() {
-    initializeFrames(kFramesCount);
-
-    while (true) {
-        {
-            scoped_lock<mutex> lock(mAccessLock);
-            if (mStreamState != RUNNING) {
-                // Break out of our main thread loop
-                LOG(INFO) << "StreamState does not equal to RUNNING. "
-                          << "Exiting the loop";
-                break;
-            }
-        }
-
-        mStream->deliverFrame_1_1(mBufferDescs);
-        std::this_thread::sleep_for(
-                std::chrono::milliseconds(kFrameGenerationDelayMillis));
-    }
-
-    {
-        scoped_lock<mutex> lock(mAccessLock);
-
-        if (mStream != nullptr) {
-            LOG(DEBUG) << "Notify EvsEventType::STREAM_STOPPED";
-
-            EvsEventDesc evsEventDesc;
-            evsEventDesc.aType = EvsEventType::STREAM_STOPPED;
-            mStream->notify(evsEventDesc);
-        } else {
-            LOG(WARNING) << "EVS stream is not valid any more. "
-                         << "The notify call is ignored.";
-        }
-    }
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.h b/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.h
deleted file mode 100644
index e06a474..0000000
--- a/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-
-#include <ConfigManager.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <mutex>
-#include <thread>
-
-using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_1::CameraParam;
-using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
-using ::android::hardware::automotive::evs::V1_1::EvsEventType;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
-using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
-using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
-using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
-using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
-using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
-using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
-using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
-using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
-
-// A simplified implementation for Evs Camera. Only necessary methods are
-// implemented.
-class MockEvsCamera : public IEvsCamera_1_1 {
-public:
-    MockEvsCamera(const std::string& cameraId, const Stream& streamCfg);
-
-    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
-    Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
-    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
-    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
-    Return<void> doneWithFrame(const BufferDesc_1_0& buffer) override;
-    Return<void> stopVideoStream() override;
-    Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
-    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
-
-    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
-    Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
-    Return<void> getPhysicalCameraInfo(const hidl_string& deviceId,
-                                       getPhysicalCameraInfo_cb _hidl_cb) override;
-    Return<EvsResult> doneWithFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) override;
-    Return<EvsResult> pauseVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
-    Return<EvsResult> resumeVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
-    Return<EvsResult> setMaster() override;
-    Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>& display) override;
-    Return<EvsResult> unsetMaster() override;
-    Return<void> getParameterList(getParameterList_cb _hidl_cb) override;
-    Return<void> getIntParameterRange(CameraParam id, getIntParameterRange_cb _hidl_cb) override;
-    Return<void> setIntParameter(CameraParam id, int32_t value,
-                                 setIntParameter_cb _hidl_cb) override;
-    Return<void> getIntParameter(CameraParam id, getIntParameter_cb _hidl_cb) override;
-    Return<EvsResult> setExtendedInfo_1_1(uint32_t opaqueIdentifier,
-                                          const hidl_vec<uint8_t>& opaqueValue) override;
-    Return<void> getExtendedInfo_1_1(uint32_t opaqueIdentifier,
-                                     getExtendedInfo_1_1_cb _hidl_cb) override;
-    Return<void> importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
-                                       importExternalBuffers_cb _hidl_cb) override;
-
-private:
-    void initializeFrames(int framesCount);
-    void generateFrames();
-
-    std::unique_ptr<ConfigManager> mConfigManager;
-
-    std::mutex mAccessLock;
-
-    enum StreamStateValues {
-        STOPPED,
-        RUNNING,
-        STOPPING,
-        DEAD,
-    };
-    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
-    Stream mStreamCfg;
-
-    std::vector<android::sp<GraphicBuffer>> mGraphicBuffers;
-    std::vector<BufferDesc_1_1> mBufferDescs;
-    CameraDesc_1_1 mCameraDesc;
-
-    std::string mCameraId;
-    std::thread mCaptureThread;  // The thread we'll use to synthesize frames
-
-    android::sp<IEvsCameraStream_1_1> mStream;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp b/cpp/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
deleted file mode 100644
index 136a81a..0000000
--- a/cpp/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "MockEvsEnumerator.h"
-#include "MockEvsCamera.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::sp;
-
-using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
-using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
-
-MockEvsEnumerator::MockEvsEnumerator() {
-    mConfigManager = ConfigManager::Create();
-}
-
-Return<void> MockEvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<sp<IEvsCamera_1_0>> MockEvsEnumerator::openCamera(
-        const hidl_string& cameraId) {
-    // Not implemented.
-
-    (void)cameraId;
-    return nullptr;
-}
-
-Return<void> MockEvsEnumerator::closeCamera(
-        const sp<IEvsCamera_1_0>& virtualCamera) {
-    // Not implemented.
-
-    (void)virtualCamera;
-    return {};
-}
-
-Return<sp<IEvsDisplay_1_0>> MockEvsEnumerator::openDisplay() {
-    // Not implemented.
-
-    return nullptr;
-}
-
-Return<void> MockEvsEnumerator::closeDisplay(
-        const sp<IEvsDisplay_1_0>& display) {
-    // Not implemented.
-
-    (void)display;
-    return {};
-}
-
-Return<EvsDisplayState> MockEvsEnumerator::getDisplayState() {
-    // Not implemented.
-
-    return EvsDisplayState::DEAD;
-}
-
-Return<void> MockEvsEnumerator::getCameraList_1_1(
-        getCameraList_1_1_cb _hidl_cb) {
-    // We only take camera group into consideration here.
-    vector<string> cameraGroupIdList = mConfigManager->getCameraGroupIdList();
-    LOG(INFO) << "getCameraGroupIdList: " << cameraGroupIdList.size();
-    for (int i = 0; i < cameraGroupIdList.size(); i++) {
-        LOG(INFO) << "Camera[" << i << "]: " << cameraGroupIdList[i];
-    }
-
-    vector<CameraDesc_1_1> hidlCameras;
-    for (int i = 0; i < cameraGroupIdList.size(); i++) {
-        CameraDesc_1_1 desc = {};
-        desc.v1.cameraId = cameraGroupIdList[i];
-        unique_ptr<ConfigManager::CameraGroupInfo>& cameraGroupInfo =
-                mConfigManager->getCameraGroupInfo(cameraGroupIdList[i]);
-        if (cameraGroupInfo != nullptr) {
-            desc.metadata.setToExternal(
-                    (uint8_t*)cameraGroupInfo->characteristics,
-                    get_camera_metadata_size(cameraGroupInfo->characteristics));
-        } else {
-            LOG(WARNING) << "Cannot find camera info for "
-                         << cameraGroupIdList[i];
-        }
-        hidlCameras.emplace_back(desc);
-    }
-    _hidl_cb(hidlCameras);
-
-    return {};
-}
-
-Return<sp<IEvsCamera_1_1>> MockEvsEnumerator::openCamera_1_1(
-        const hidl_string& cameraId, const Stream& streamCfg) {
-    LOG(INFO) << __FUNCTION__ << ": " << streamCfg.width << ", " << streamCfg.height;
-    return new MockEvsCamera(cameraId, streamCfg);
-}
-
-Return<void> MockEvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
-    // Not implemented.
-
-    (void)_list_cb;
-    return {};
-}
-
-Return<sp<IEvsDisplay_1_1>> MockEvsEnumerator::openDisplay_1_1(uint8_t id) {
-    // Not implemented.
-
-    (void)id;
-    return nullptr;
-}
-
-Return<void> MockEvsEnumerator::getUltrasonicsArrayList(
-        getUltrasonicsArrayList_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)_hidl_cb;
-    return {};
-}
-
-Return<sp<IEvsUltrasonicsArray>> MockEvsEnumerator::openUltrasonicsArray(
-        const hidl_string& ultrasonicsArrayId) {
-    // Not implemented.
-
-    (void)ultrasonicsArrayId;
-    return nullptr;
-}
-
-Return<void> MockEvsEnumerator::closeUltrasonicsArray(
-        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) {
-    // Not implemented.
-
-    (void)evsUltrasonicsArray;
-    return {};
-}
-
-Return<void> MockEvsEnumerator::debug(
-        const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
-    // Not implemented.
-
-    (void)fd;
-    (void)options;
-    return {};
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/mock-evs/MockEvsEnumerator.h b/cpp/surround_view/service-impl/mock-evs/MockEvsEnumerator.h
deleted file mode 100644
index 7c1f8b0..0000000
--- a/cpp/surround_view/service-impl/mock-evs/MockEvsEnumerator.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <system/camera_metadata.h>
-
-#include <ConfigManager.h>
-
-using namespace ::android::hardware::automotive::evs::V1_1;
-using ::android::hardware::camera::device::V3_2::Stream;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
-using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
-using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
-using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
-using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
-using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
-
-class MockEvsEnumerator : public IEvsEnumerator_1_1 {
-public:
-    MockEvsEnumerator();
-
-    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
-    Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
-    Return<sp<IEvsCamera_1_0>> openCamera(const hidl_string& cameraId) override;
-    Return<void> closeCamera(const ::android::sp<IEvsCamera_1_0>& virtualCamera) override;
-    Return<sp<IEvsDisplay_1_0>> openDisplay() override;
-    Return<void> closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display) override;
-    Return<EvsDisplayState> getDisplayState() override;
-
-    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
-    Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
-    Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
-                                              const Stream& streamCfg) override;
-    Return<bool> isHardware() override { return false; }
-    Return<void> getDisplayIdList(getDisplayIdList_cb _list_cb) override;
-    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t id) override;
-    Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
-    Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
-            const hidl_string& ultrasonicsArrayId) override;
-    Return<void> closeUltrasonicsArray(
-            const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) override;
-
-    // Methods from ::android.hidl.base::V1_0::IBase follow.
-    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
-
-private:
-    std::unique_ptr<ConfigManager> mConfigManager;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp b/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
deleted file mode 100644
index 60108e6..0000000
--- a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#include "MockSurroundViewCallback.h"
-
-#include <android-base/logging.h>
-
-#include <thread>
-
-using ::android::sp;
-using ::android::hardware::Return;
-
-using ::std::thread;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-MockSurroundViewCallback::MockSurroundViewCallback(
-        sp<ISurroundViewSession> pSession) :
-        mSession(pSession) {}
-
-Return<void> MockSurroundViewCallback::notify(SvEvent svEvent) {
-    LOG(INFO) << __FUNCTION__ << "SvEvent received: " << (int)svEvent;
-    return {};
-}
-
-Return<void> MockSurroundViewCallback::receiveFrames(
-        const SvFramesDesc& svFramesDesc) {
-    LOG(INFO) << __FUNCTION__ << svFramesDesc.svBuffers.size()
-              << " frames are received";
-
-    // Increment the count of received frames.
-    {
-        std::scoped_lock<std::mutex> lock(mAccessLock);
-        mReceivedFramesCount++;
-    }
-
-    // Create a separate thread to return the frames to the session. This
-    // simulates the behavior of oneway HIDL method call.
-    thread mockHidlThread([this, &svFramesDesc]() {
-        mSession->doneWithFrames(svFramesDesc);
-    });
-    mockHidlThread.detach();
-    return {};
-}
-
-int MockSurroundViewCallback::getReceivedFramesCount() {
-    {
-        std::scoped_lock<std::mutex> lock(mAccessLock);
-        return mReceivedFramesCount;
-    }
-}
-
-void MockSurroundViewCallback::clearReceivedFramesCount() {
-    {
-        std::scoped_lock<std::mutex> lock(mAccessLock);
-        mReceivedFramesCount = 0;
-    }
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h b/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
deleted file mode 100644
index 238e41a..0000000
--- a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <mutex>
-#include <thread>
-
-using namespace android::hardware::automotive::sv::V1_0;
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace sv {
-namespace V1_0 {
-namespace implementation {
-
-class MockSurroundViewCallback : public ISurroundViewStream {
-public:
-    MockSurroundViewCallback(android::sp<ISurroundViewSession> pSession);
-
-    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewStream.
-    android::hardware::Return<void> notify(SvEvent svEvent) override;
-    android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
-
-    // Methods to get and clear the mReceivedFramesCount.
-    int getReceivedFramesCount();
-    void clearReceivedFramesCount();
-private:
-    std::mutex mAccessLock;
-    android::sp<ISurroundViewSession> mSession;
-
-    // Keeps a count of the number of calls made to receiveFrames().
-    int mReceivedFramesCount GUARDED_BY(mAccessLock) = 0;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace sv
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/cpp/surround_view/service-impl/service.cpp b/cpp/surround_view/service-impl/service.cpp
deleted file mode 100644
index b7d82f7..0000000
--- a/cpp/surround_view/service-impl/service.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-
-#include <android-base/logging.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
-#include <android/hardware_buffer.h>
-#include <hidl/HidlTransportSupport.h>
-#include <thread>
-#include <ui/GraphicBuffer.h>
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-#include <utils/SystemClock.h>
-#include <utils/Trace.h>
-
-#include "SurroundViewService.h"
-
-// libhidl:
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-
-// implementation:
-using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
-
-int main() {
-    LOG(INFO) << "ISurroundViewService default implementation is starting";
-    android::sp<ISurroundViewService> service = SurroundViewService::getInstance();
-
-    configureRpcThreadpool(1, true /* callerWillJoin */);
-
-    ATRACE_BEGIN("SurroundViewServiceImpl: registerAsService");
-
-    // Register our service -- if somebody is already registered by our name,
-    // they will be killed (their thread pool will throw an exception).
-    android::status_t status = service->registerAsService();
-
-    if (status != android::OK) {
-        LOG(ERROR) << "Could not register default Surround View Service. Status: "
-                   << status;
-    }
-
-    ATRACE_END();
-
-    joinRpcThreadpool();
-
-    // In normal operation, we don't expect the thread pool to exit
-    LOG(ERROR) << "Surround View Service is shutting down";
-    return 1;
-}
diff --git a/cpp/surround_view/service-impl/sv_3d_params.h b/cpp/surround_view/service-impl/sv_3d_params.h
deleted file mode 100644
index 0b6c223..0000000
--- a/cpp/surround_view/service-impl/sv_3d_params.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#ifndef SV_3D_PARAMS_H
-#define SV_3D_PARAMS_H
-
-#include <vector>
-#include <hidl/HidlSupport.h>
-
-using ::android::hardware::hidl_vec;
-
-static std::vector<android::hardware::hidl_vec<float>> kRecViews = {
-    {0, 1, -0, -0, -0.747409, 0, 0.664364, 1.32873, 0.664364, -0, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-0.382683, 0.92388, 0, -0, -0.690516, -0.286021, 0.664364, 1.32873, 0.613792, 0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-0.707107, 0.707107, 0, -0, -0.528498, -0.528498, 0.664364, 1.32873, 0.469776, 0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-0.92388, 0.382683, 0, -1.19209e-07, -0.286021, -0.690516, 0.664364, 1.32873, 0.254241, 0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-1, -4.37114e-08, 0, -0, 3.26703e-08, -0.747409, 0.664364, 1.32873, -2.90403e-08, 0.664364, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-0.92388, -0.382683, 0, -0, 0.286021, -0.690516, 0.664364, 1.32873, -0.254241, 0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-0.707107, -0.707107, 0, -0, 0.528498, -0.528498, 0.664364, 1.32873, -0.469776, 0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
-    {-0.382683, -0.92388, 0, 1.19209e-07, 0.690516, -0.286021, 0.664364, 1.32873, -0.613792, 0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
-    {8.74228e-08, -1, 0, -0, 0.747409, 6.53406e-08, 0.664364, 1.32873, -0.664364, -5.80805e-08, 0.747409, -4.52598, 0, 0, 0, 1},
-    {0.382683, -0.92388, 0, 1.19209e-07, 0.690516, 0.286021, 0.664364, 1.32873, -0.613792, -0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
-    {0.707107, -0.707107, 0, 1.19209e-07, 0.528498, 0.528498, 0.664364, 1.32873, -0.469776, -0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
-    {0.92388, -0.382684, 0, 1.19209e-07, 0.286021, 0.690516, 0.664364, 1.32873, -0.254241, -0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
-    {1, 1.19249e-08, -0, 3.55271e-15, -8.91277e-09, 0.747409, 0.664364, 1.32873, 7.92246e-09, -0.664364, 0.747409, -4.52598, 0, 0, 0, 1},
-    {0.92388, 0.382684, -0, -0, -0.286021, 0.690516, 0.664364, 1.32873, 0.254241, -0.613792, 0.747409, -4.52598, 0, 0, 0, 1},
-    {0.707107, 0.707107, -0, -1.19209e-07, -0.528498, 0.528498, 0.664364, 1.32873, 0.469776, -0.469776, 0.747409, -4.52598, 0, 0, 0, 1},
-    {0.382683, 0.92388, -0, -1.19209e-07, -0.690516, 0.286021, 0.664364, 1.32873, 0.613792, -0.254241, 0.747409, -4.52598, 0, 0, 0, 1},
-};
-
-#endif // SV_3D_PARAMS_H
-
diff --git a/cpp/surround_view/service-impl/test_data/0.png b/cpp/surround_view/service-impl/test_data/0.png
deleted file mode 100644
index 283751b..0000000
--- a/cpp/surround_view/service-impl/test_data/0.png
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/test_data/1.png b/cpp/surround_view/service-impl/test_data/1.png
deleted file mode 100644
index 55abd66..0000000
--- a/cpp/surround_view/service-impl/test_data/1.png
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/test_data/2.png b/cpp/surround_view/service-impl/test_data/2.png
deleted file mode 100644
index c66dd61..0000000
--- a/cpp/surround_view/service-impl/test_data/2.png
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/test_data/3.png b/cpp/surround_view/service-impl/test_data/3.png
deleted file mode 100644
index f9d2c60..0000000
--- a/cpp/surround_view/service-impl/test_data/3.png
+++ /dev/null
Binary files differ
diff --git a/cpp/surround_view/service-impl/test_data/sample_car.obj b/cpp/surround_view/service-impl/test_data/sample_car.obj
deleted file mode 100644
index 3600a7b..0000000
--- a/cpp/surround_view/service-impl/test_data/sample_car.obj
+++ /dev/null
@@ -1,64 +0,0 @@
-# Sample Car Model Obj files
-# Consist of cubes representing a car part
-
-mtllib sample_car_material.mtl
-
-# Car Door Object
-v 0.0 0.0 0.0
-v 0.0 0.0 1.0
-v 0.0 1.0 0.0
-v 0.0 1.0 1.0
-v 1.0 0.0 0.0
-v 1.0 0.0 1.0
-v 1.0 1.0 0.0
-v 1.0 1.0 1.0
-vn 0.0 0.0 1.0
-vn 0.0 0.0 -1.0
-vn 0.0 1.0 0.0
-vn 0.0 -1.0 0.0
-vn 1.0 0.0 0.0
-vn -1.0 0.0 0.0
-g door
-usemtl door
-f 1//2 7//2 5//2
-f 1//2 3//2 7//2
-f 1//6 4//6 3//6
-f 1//6 2//6 4//6
-f 3//3 8//3 7//3
-f 3//3 4//3 8//3
-f 5//5 7//5 8//5
-f 5//5 8//5 6//5
-f 1//4 5//4 6//4
-f 1//4 6//4 2//4
-f 2//1 6//1 8//1
-f 2//1 8//1 4//1
-
-# Car Window Object
-v 0.0 0.0 0.0
-v 0.0 0.0 -1.0
-v 0.0 -1.0 0.0
-v 0.0 -1.0 1.0
-v -1.0 0.0 0.0
-v -1.0 0.0 -1.0
-v -1.0 -1.0 0.0
-v -1.0 -1.0 -1.0
-vn 0.0 0.0 1.0
-vn 0.0 0.0 -1.0
-vn 0.0 1.0 0.0
-vn 0.0 -1.0 0.0
-vn 1.0 0.0 0.0
-vn -1.0 0.0 0.0
-g window
-usemtl window
-f 1//2 7//2 5//2
-f 1//2 3//2 7//2
-f 1//6 4//6 3//6
-f 1//6 2//6 4//6
-f 3//3 8//3 7//3
-f 3//3 4//3 8//3
-f 5//5 7//5 8//5
-f 5//5 8//5 6//5
-f 1//4 5//4 6//4
-f 1//4 6//4 2//4
-f 2//1 6//1 8//1
-f 2//1 8//1 4//1
diff --git a/cpp/surround_view/service-impl/test_data/sample_car_material.mtl b/cpp/surround_view/service-impl/test_data/sample_car_material.mtl
deleted file mode 100644
index aaa2f1b..0000000
--- a/cpp/surround_view/service-impl/test_data/sample_car_material.mtl
+++ /dev/null
@@ -1,18 +0,0 @@
-# Sample material file for car model.
-# referenced by sample_car.obj
-
-newmtl door
-    d 1.0000
-    illum 1
-    Ka 0.5000 0.5000 0.5000
-    Kd 1.0000 1.0000 1.0000
-    Ks 1.0000 1.0000 1.0000
-    ns 0.0000
-
-newmtl window
-    d 1.0000
-    illum 1
-    Ka 0.5000 0.5000 0.5000
-    Kd 1.0000 0.0000 0.0000
-    Ks 1.0000 1.0000 1.0000
-    ns 0.0000
diff --git a/cpp/surround_view/service-impl/test_data/sv_sample_car_model_config.xml b/cpp/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
deleted file mode 100644
index 60541a8..0000000
--- a/cpp/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<SurroundViewCarModelConfig>
-    <Version>1.0</Version>
-
-    <!-- Rotation animation for door -->
-    <Animation>
-        <PartId>door</PartId>
-        <ChildParts>
-            <PartId>window</PartId>
-        </ChildParts>
-        <ParentPartId>car_frame</ParentPartId>
-        <RotationOp>
-            <VhalProperty>
-                <!-- Uses VHAL Property DOOR_POS -->
-                <PropertyId>0x16000B00</PropertyId>
-                <!-- AreadId = VehicleAreaDoor::ROW_1_LEFT -->
-                <AreaId>0x00000001</AreaId>
-            </VhalProperty>
-            <AnimationType>RotationAngle</AnimationType>
-            <AnimationTimeMs>2000</AnimationTimeMs>
-            <RotationAxis>
-                <X>0.0</X>
-                <Y>0.0</Y>
-                <Z>1.0</Z>
-            </RotationAxis>
-            <RotationPoint>
-                <X>0.0</X>
-                <Y>0.0</Y>
-                <Z>0.0</Z>
-            </RotationPoint>
-            <DefaultRotationValue>0.0</DefaultRotationValue>
-            <RotationRange>
-                <Start>0.0</Start>
-                <End>90</End>
-            </RotationRange>
-            <VhalRange>
-                <!-- 0 => door closed -->
-                <Start>0x00000000</Start>
-                <!-- INT32_MAX => door fully open -->
-                <End>0x7FFFFFFF</End>
-            </VhalRange>
-        </RotationOp>
-    </Animation>
-
-    <!-- Translation animation for window -->
-    <Animation>
-        <PartId>window</PartId>
-        <ParentPartId>window</ParentPartId>
-        <ChildParts>
-        </ChildParts>
-        <TranslationOp>
-            <VhalProperty>
-                <!-- Uses VHAL Property WINDOW_POS -->
-                <PropertyId>0x13000BC0</PropertyId>
-                <!-- AreaId = VehicleAreaWindow::ROW_1_LEFT -->
-                <AreaId>0x00000010</AreaId>
-            </VhalProperty>
-            <AnimationType>Translation</AnimationType>
-            <AnimationTimeMs>2000</AnimationTimeMs>
-            <Direction>
-                <X>0.0</X>
-                <Y>0.0</Y>
-                <Z>-1.0</Z>
-            </Direction>
-            <DefaultTranslationValue>0.0</DefaultTranslationValue>
-            <TranslationRange>
-                <Start>0.0</Start>
-                <End>1.0</End>
-            </TranslationRange>
-            <VhalRange>
-                <!-- 0 => window up/closed -->
-                <Start>0x00000000</Start>
-                <!-- INT32_MAX => window down/open -->
-                <End>0x7FFFFFFF</End>
-            </VhalRange>
-        </TranslationOp>
-    </Animation>
-
-</SurroundViewCarModelConfig>
diff --git a/cpp/surround_view/service-impl/test_data/sv_sample_config.xml b/cpp/surround_view/service-impl/test_data/sv_sample_config.xml
deleted file mode 100644
index 1a92bee..0000000
--- a/cpp/surround_view/service-impl/test_data/sv_sample_config.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<SurroundViewConfig>
-    <Version>1.0</Version>
-
-    <CameraConfig>
-        <EvsGroupId>v4l2loopback_group0</EvsGroupId>
-        <EvsCameraIds>
-            <Front>/dev/video60</Front>
-            <Right>/dev/video61</Right>
-            <Rear>/dev/video62</Rear>
-            <Left>/dev/video63</Left>
-        </EvsCameraIds>
-        <Masks>
-            <Front>/vendor/etc/automotive/sv/mask_front.png</Front>
-            <Right>/vendor/etc/automotive/sv/mask_right.png</Right>
-            <Rear>/vendor/etc/automotive/sv/mask_rear.png</Rear>
-            <Left>/vendor/etc/automotive/sv/mask_left.png</Left>
-        </Masks>
-    </CameraConfig>
-
-    <Sv2dEnabled>true</Sv2dEnabled>
-    <Sv2dParams>
-        <OutputResolution>
-            <Width>1200</Width>
-            <Height>1600</Height>
-        </OutputResolution>
-        <GroundMapping>
-            <Width>9.0</Width>
-            <Height>12.0</Height>
-            <Center>
-                <X>0.0</X>
-                <Y>0.0</Y>
-            </Center>
-        </GroundMapping>
-        <CarBoundingBox>
-            <Width>2.0</Width>
-            <Height>3.0</Height>
-            <LeftTopCorner>
-                <X>1.0</X>
-                <Y>1.5</Y>
-            </LeftTopCorner>
-        </CarBoundingBox>
-        <BlendingType>
-            <HighQuality>multiband</HighQuality>
-            <LowQuality>alpha</LowQuality>
-        </BlendingType>
-        <GpuAccelerationEnabled>true</GpuAccelerationEnabled>
-    </Sv2dParams>
-
-    <Sv3dEnabled>true</Sv3dEnabled>
-    <Sv3dAnimationsEnabled>true</Sv3dAnimationsEnabled>
-    <CarModelConfigFile>/vendor/etc/automotive/sv/sv_sample_car_model_config.xml</CarModelConfigFile>
-    <CarModelObjFile>/vendor/etc/automotive/sv/sample_car.obj</CarModelObjFile>
-    <Sv3dParams>
-        <OutputResolution>
-            <Width>1920</Width>
-            <Height>1080</Height>
-        </OutputResolution>
-        <BowlParams>
-            <PlaneRadius>8.0</PlaneRadius>
-            <PlaneDivisions>50</PlaneDivisions>
-            <CurveHeight>6.0</CurveHeight>
-            <CurveDivisions>50</CurveDivisions>
-            <AngularDivisions>90</AngularDivisions>
-            <CurveCoefficient>3.0</CurveCoefficient>
-        </BowlParams>
-        <HighQualityDetails>
-            <Shadows>true</Shadows>
-            <Reflections>true</Reflections>
-        </HighQualityDetails>
-    </Sv3dParams>
-</SurroundViewConfig>
diff --git a/cpp/telemetry/proto/CarData.proto b/cpp/telemetry/proto/CarData.proto
index 96e8c2e..3440689 100644
--- a/cpp/telemetry/proto/CarData.proto
+++ b/cpp/telemetry/proto/CarData.proto
@@ -31,6 +31,11 @@
 
 import "packages/services/Car/cpp/telemetry/proto/evs.proto";
 
+// Contains all the CarData messages to declare all the messages.
+// Unique protobuf number is used as an ID.
+// A message will be sent from writer clients to the cartelemetryd
+// wrapped in
+// frameworks/hardware/interfaces/automotive/telemetry/aidl/android/frameworks/automotive/telemetry/CarData.aidl
 message CarData {
   oneof pushed {
     EvsFirstFrameLatency evs_first_frame_latency = 1;
diff --git a/cpp/telemetry/script_executor/Android.bp b/cpp/telemetry/script_executor/Android.bp
index 6eaec62..9d8a05b 100644
--- a/cpp/telemetry/script_executor/Android.bp
+++ b/cpp/telemetry/script_executor/Android.bp
@@ -34,6 +34,7 @@
         "scriptexecutor_defaults",
     ],
     srcs: [
+        "src/BundleWrapper.cpp",
         "src/JniUtils.cpp",
         "src/LuaEngine.cpp",
         "src/ScriptExecutorListener.cpp",
diff --git a/cpp/telemetry/script_executor/src/BundleWrapper.cpp b/cpp/telemetry/script_executor/src/BundleWrapper.cpp
new file mode 100644
index 0000000..77d2a5f
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/BundleWrapper.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021, 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.
+ */
+
+#include "BundleWrapper.h"
+
+#include <android-base/logging.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+BundleWrapper::BundleWrapper(JNIEnv* env) {
+    mJNIEnv = env;
+    mBundleClass =
+            static_cast<jclass>(mJNIEnv->NewGlobalRef(mJNIEnv->FindClass("android/os/Bundle")));
+    jmethodID bundleConstructor = mJNIEnv->GetMethodID(mBundleClass, "<init>", "()V");
+    mBundle = mJNIEnv->NewGlobalRef(mJNIEnv->NewObject(mBundleClass, bundleConstructor));
+}
+
+BundleWrapper::~BundleWrapper() {
+    // Delete global JNI references.
+    if (mBundle != NULL) {
+        mJNIEnv->DeleteGlobalRef(mBundle);
+    }
+    if (mBundleClass != NULL) {
+        mJNIEnv->DeleteGlobalRef(mBundleClass);
+    }
+}
+
+void BundleWrapper::putBoolean(const char* key, bool value) {
+    jmethodID putBooleanMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putBoolean", "(Ljava/lang/String;Z)V");
+    mJNIEnv->CallVoidMethod(mBundle, putBooleanMethod, mJNIEnv->NewStringUTF(key),
+                            static_cast<jboolean>(value));
+}
+
+void BundleWrapper::putInteger(const char* key, int value) {
+    jmethodID putIntMethod = mJNIEnv->GetMethodID(mBundleClass, "putInt", "(Ljava/lang/String;I)V");
+    mJNIEnv->CallVoidMethod(mBundle, putIntMethod, mJNIEnv->NewStringUTF(key),
+                            static_cast<jint>(value));
+}
+
+void BundleWrapper::putDouble(const char* key, double value) {
+    jmethodID putDoubleMethod =
+            mJNIEnv->GetMethodID(mBundleClass, "putDouble", "(Ljava/lang/String;D)V");
+    mJNIEnv->CallVoidMethod(mBundle, putDoubleMethod, mJNIEnv->NewStringUTF(key),
+                            static_cast<jdouble>(value));
+}
+
+void BundleWrapper::putString(const char* key, const char* value) {
+    jmethodID putStringMethod = mJNIEnv->GetMethodID(mBundleClass, "putString",
+                                                     "(Ljava/lang/String;Ljava/lang/String;)V");
+    mJNIEnv->CallVoidMethod(mBundle, putStringMethod, mJNIEnv->NewStringUTF(key),
+                            mJNIEnv->NewStringUTF(value));
+}
+
+jobject BundleWrapper::getBundle() {
+    return mBundle;
+}
+
+}  // namespace script_executor
+}  // namespace telemetry
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/telemetry/script_executor/src/BundleWrapper.h b/cpp/telemetry/script_executor/src/BundleWrapper.h
new file mode 100644
index 0000000..8c42c46
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/BundleWrapper.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, 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.
+ */
+
+#ifndef CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_BUNDLEWRAPPER_H_
+#define CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_BUNDLEWRAPPER_H_
+
+#include "jni.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+// Used to create a java bundle object and populate its fields one at a time.
+class BundleWrapper {
+public:
+    explicit BundleWrapper(JNIEnv* env);
+    // BundleWrapper is not copyable.
+    BundleWrapper(const BundleWrapper&) = delete;
+    BundleWrapper& operator=(const BundleWrapper&) = delete;
+
+    virtual ~BundleWrapper();
+
+    // Family of methods that puts the provided 'value' into the Bundle under provided 'key'.
+    void putBoolean(const char* key, bool value);
+    void putInteger(const char* key, int value);
+    void putDouble(const char* key, double value);
+    void putString(const char* key, const char* value);
+
+    jobject getBundle();
+
+private:
+    // The class asks Java to create Bundle object and stores the reference.
+    // When the instance of this class is destroyed the actual Java Bundle object behind
+    // this reference stays on and is managed by Java.
+    jobject mBundle;
+
+    // Reference to java Bundle class cached for performance reasons.
+    jclass mBundleClass;
+
+    // Stores a JNIEnv* pointer.
+    JNIEnv* mJNIEnv;  // not owned
+};
+
+}  // namespace script_executor
+}  // namespace telemetry
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_BUNDLEWRAPPER_H_
diff --git a/cpp/telemetry/script_executor/src/JniUtils.cpp b/cpp/telemetry/script_executor/src/JniUtils.cpp
index 93c1af8..cfe1da4 100644
--- a/cpp/telemetry/script_executor/src/JniUtils.cpp
+++ b/cpp/telemetry/script_executor/src/JniUtils.cpp
@@ -21,8 +21,8 @@
 namespace telemetry {
 namespace script_executor {
 
-void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
-    lua_newtable(luaEngine->GetLuaState());
+void pushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
+    lua_newtable(luaEngine->getLuaState());
     // null bundle object is allowed. We will treat it as an empty table.
     if (bundle == nullptr) {
         return;
@@ -62,19 +62,19 @@
         if (env->IsInstanceOf(value, booleanClass)) {
             jmethodID boolMethod = env->GetMethodID(booleanClass, "booleanValue", "()Z");
             bool boolValue = static_cast<bool>(env->CallBooleanMethod(value, boolMethod));
-            lua_pushboolean(luaEngine->GetLuaState(), boolValue);
+            lua_pushboolean(luaEngine->getLuaState(), boolValue);
         } else if (env->IsInstanceOf(value, integerClass)) {
             jmethodID intMethod = env->GetMethodID(integerClass, "intValue", "()I");
-            lua_pushinteger(luaEngine->GetLuaState(), env->CallIntMethod(value, intMethod));
+            lua_pushinteger(luaEngine->getLuaState(), env->CallIntMethod(value, intMethod));
         } else if (env->IsInstanceOf(value, numberClass)) {
             // Condense other numeric types using one class. Because lua supports only
             // integer or double, and we handled integer in previous if clause.
             jmethodID numberMethod = env->GetMethodID(numberClass, "doubleValue", "()D");
             /* Pushes a double onto the stack */
-            lua_pushnumber(luaEngine->GetLuaState(), env->CallDoubleMethod(value, numberMethod));
+            lua_pushnumber(luaEngine->getLuaState(), env->CallDoubleMethod(value, numberMethod));
         } else if (env->IsInstanceOf(value, stringClass)) {
             const char* rawStringValue = env->GetStringUTFChars((jstring)value, nullptr);
-            lua_pushstring(luaEngine->GetLuaState(), rawStringValue);
+            lua_pushstring(luaEngine->getLuaState(), rawStringValue);
             env->ReleaseStringUTFChars((jstring)value, rawStringValue);
         } else {
             // Other types are not implemented yet, skipping.
@@ -84,7 +84,7 @@
         const char* rawKey = env->GetStringUTFChars(key, nullptr);
         // table[rawKey] = value, where value is on top of the stack,
         // and the table is the next element in the stack.
-        lua_setfield(luaEngine->GetLuaState(), /* idx= */ -2, rawKey);
+        lua_setfield(luaEngine->getLuaState(), /* idx= */ -2, rawKey);
         env->ReleaseStringUTFChars(key, rawKey);
     }
 }
diff --git a/cpp/telemetry/script_executor/src/JniUtils.h b/cpp/telemetry/script_executor/src/JniUtils.h
index c3ef677..85034d7 100644
--- a/cpp/telemetry/script_executor/src/JniUtils.h
+++ b/cpp/telemetry/script_executor/src/JniUtils.h
@@ -29,7 +29,7 @@
 // converted to the corresponding key-value pairs of the Lua table as long as
 // the Bundle value types are supported. At this point, we support boolean,
 // integer, double and String types in Java.
-void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
+void pushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
 
 }  // namespace script_executor
 }  // namespace telemetry
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.cpp b/cpp/telemetry/script_executor/src/LuaEngine.cpp
index 1a074f2..e2bcef7 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.cpp
+++ b/cpp/telemetry/script_executor/src/LuaEngine.cpp
@@ -16,10 +16,15 @@
 
 #include "LuaEngine.h"
 
+#include "BundleWrapper.h"
+
+#include <android-base/logging.h>
+
 #include <utility>
 
 extern "C" {
 #include "lauxlib.h"
+#include "lua.h"
 #include "lualib.h"
 }
 
@@ -28,6 +33,16 @@
 namespace telemetry {
 namespace script_executor {
 
+namespace {
+
+enum LuaNumReturnedResults {
+    ZERO_RETURNED_RESULTS = 0,
+};
+
+}  // namespace
+
+ScriptExecutorListener* LuaEngine::sListener = nullptr;
+
 LuaEngine::LuaEngine() {
     // Instantiate Lua environment
     mLuaState = luaL_newstate();
@@ -38,15 +53,18 @@
     lua_close(mLuaState);
 }
 
-lua_State* LuaEngine::GetLuaState() {
+lua_State* LuaEngine::getLuaState() {
     return mLuaState;
 }
 
-void LuaEngine::ResetListener(ScriptExecutorListener* listener) {
-    mListener.reset(listener);
+void LuaEngine::resetListener(ScriptExecutorListener* listener) {
+    if (sListener != nullptr) {
+        delete sListener;
+    }
+    sListener = listener;
 }
 
-int LuaEngine::LoadScript(const char* scriptBody) {
+int LuaEngine::loadScript(const char* scriptBody) {
     // As the first step in Lua script execution we want to load
     // the body of the script into Lua stack and have it processed by Lua
     // to catch any errors.
@@ -61,11 +79,15 @@
         // Starting read about Lua stack: https://www.lua.org/pil/24.2.html
         // TODO(b/192284232): add test case to trigger this.
         lua_pop(mLuaState, 1);
+        return status;
     }
+
+    // Register limited set of reserved methods for Lua to call native side.
+    lua_register(mLuaState, "on_success", LuaEngine::onSuccess);
     return status;
 }
 
-bool LuaEngine::PushFunction(const char* functionName) {
+bool LuaEngine::pushFunction(const char* functionName) {
     // Interaction between native code and Lua happens via Lua stack.
     // In such model, a caller first pushes the name of the function
     // that needs to be called, followed by the function's input
@@ -78,7 +100,7 @@
     return status;
 }
 
-int LuaEngine::Run() {
+int LuaEngine::run() {
     // Performs blocking call of the provided Lua function. Assumes all
     // input arguments are in the Lua stack as well in proper order.
     // On how to call Lua functions: https://www.lua.org/pil/25.2.html
@@ -89,6 +111,54 @@
     return lua_pcall(mLuaState, /* nargs= */ 1, /* nresults= */ 0, /*errfunc= */ 0);
 }
 
+int LuaEngine::onSuccess(lua_State* lua) {
+    if (sListener == nullptr) {
+        LOG(FATAL) << "sListener object must not be null";
+    }
+    // Any script we run can call on_success only with a single argument of Lua table type.
+    if (lua_gettop(lua) != 1 || !lua_istable(lua, /* index =*/-1)) {
+        // TODO(b/193565932): Return programming error through binder callback interface.
+        LOG(ERROR) << "Only a single input argument, a Lua table object, expected here";
+    }
+
+    // Helper object to create and populate Java Bundle object.
+    BundleWrapper bundleWrapper(sListener->getCurrentJNIEnv());
+    // Iterate over Lua table which is expected to be at the top of Lua stack.
+    // lua_next call pops the key from the top of the stack and finds the next
+    // key-value pair for the popped key. It returns 0 if the next pair was not found.
+    // More on lua_next in: https://www.lua.org/manual/5.3/manual.html#lua_next
+    lua_pushnil(lua);  // First key is a null value.
+    while (lua_next(lua, /* index =*/-2) != 0) {
+        //  'key' is at index -2 and 'value' is at index -1
+        // -1 index is the top of the stack.
+        // remove 'value' and keep 'key' for next iteration
+        // Process each key-value depending on a type and push it to Java Bundle.
+        const char* key = lua_tostring(lua, /* index =*/-2);
+        if (lua_isboolean(lua, /* index =*/-1)) {
+            bundleWrapper.putBoolean(key, static_cast<bool>(lua_toboolean(lua, /* index =*/-1)));
+        } else if (lua_isinteger(lua, /* index =*/-1)) {
+            bundleWrapper.putInteger(key, static_cast<int>(lua_tointeger(lua, /* index =*/-1)));
+        } else if (lua_isnumber(lua, /* index =*/-1)) {
+            bundleWrapper.putDouble(key, static_cast<double>(lua_tonumber(lua, /* index =*/-1)));
+        } else if (lua_isstring(lua, /* index =*/-1)) {
+            bundleWrapper.putString(key, lua_tostring(lua, /* index =*/-1));
+        } else {
+            // not supported yet...
+            LOG(WARNING) << "key=" << key << " has a Lua type which is not supported yet. "
+                         << "The bundle object will not have this key-value pair.";
+        }
+        // Pop 1 element from the stack.
+        lua_pop(lua, 1);
+        // The key is at index -1, the table is at index -2 now.
+    }
+
+    // Forward the populated Bundle object to Java callback.
+    sListener->onSuccess(bundleWrapper.getBundle());
+    // We explicitly must tell Lua how many results we return, which is 0 in this case.
+    // More on the topic: https://www.lua.org/manual/5.3/manual.html#lua_CFunction
+    return ZERO_RETURNED_RESULTS;
+}
+
 }  // namespace script_executor
 }  // namespace telemetry
 }  // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.h b/cpp/telemetry/script_executor/src/LuaEngine.h
index a1d6e48..39f3a9f 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.h
+++ b/cpp/telemetry/script_executor/src/LuaEngine.h
@@ -38,30 +38,47 @@
     virtual ~LuaEngine();
 
     // Returns pointer to Lua state object.
-    lua_State* GetLuaState();
+    lua_State* getLuaState();
 
     // Loads Lua script provided as scriptBody string.
     // Returns 0 if successful. Otherwise returns non-zero Lua error code.
-    int LoadScript(const char* scriptBody);
+    int loadScript(const char* scriptBody);
 
     // Pushes a Lua function under provided name into the stack.
     // Returns true if successful.
-    bool PushFunction(const char* functionName);
+    bool pushFunction(const char* functionName);
 
     // Invokes function with the inputs provided in the stack.
-    // Assumes that the script body has been already loaded and successully
+    // Assumes that the script body has been already loaded and successfully
     // compiled and run, and all input arguments, and the function have been
     // pushed to the stack.
     // Returns 0 if successful. Otherwise returns non-zero Lua error code.
-    int Run();
+    int run();
 
     // Updates stored listener and destroys the previous one.
-    void ResetListener(ScriptExecutorListener* listener);
+    static void resetListener(ScriptExecutorListener* listener);
 
 private:
-    lua_State* mLuaState;  // owned
+    // Invoked by running Lua script to store intermediate results.
+    // The script will provide the results as a Lua table.
+    // We currently support only non-nested fields in the table and the fields can be the following
+    // Lua types: boolean, number, integer, and string.
+    // The result is converted to Android Bundle and forwarded to
+    // ScriptExecutor service via callback interface.
+    static int onSuccess(lua_State* lua);
 
-    std::unique_ptr<ScriptExecutorListener> mListener;
+    // Points to the current listener object.
+    // Lua cannot call non-static class methods. We need to access listener object instance in
+    // Lua callbacks. Therefore, callbacks callable by Lua are static class methods and the pointer
+    // to a listener object needs to be static, since static methods cannot access non-static
+    // members.
+    // Only one listener is supported at any given time.
+    // Since listeners are heap-allocated, the destructor does not need to run at shutdown
+    // of the service because the memory allocated to the current listener object will be
+    // reclaimed by the OS.
+    static ScriptExecutorListener* sListener;
+
+    lua_State* mLuaState;  // owned
 };
 
 }  // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp b/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp
index 500b8e2..0bdc692 100644
--- a/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp
+++ b/cpp/telemetry/script_executor/src/ScriptExecutorJni.cpp
@@ -65,9 +65,8 @@
 // More information about how to work with Lua stack: https://www.lua.org/pil/24.2.html
 // and how Lua functions are called via Lua API: https://www.lua.org/pil/25.2.html
 //
-// Finally, once parsing and pushing to Lua stack is complete, we do
-//
-// Step 6: attempt to run the provided function.
+// Finally, once parsing and pushing to Lua stack is complete, we go on to the final step,
+// Step 6: Attempt to run the provided function.
 JNIEXPORT void JNICALL Java_com_android_car_telemetry_ScriptExecutor_nativeInvokeScript(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jstring scriptBody, jstring functionName,
         jobject publishedData, jobject savedState, jobject listener) {
@@ -88,7 +87,7 @@
 
     // Load and parse the script
     const char* scriptStr = env->GetStringUTFChars(scriptBody, nullptr);
-    auto status = engine->LoadScript(scriptStr);
+    auto status = engine->loadScript(scriptStr);
     env->ReleaseStringUTFChars(scriptBody, scriptStr);
     // status == 0 if the script loads successfully.
     if (status) {
@@ -96,11 +95,11 @@
                       "Failed to load the script.");
         return;
     }
-    engine->ResetListener(new ScriptExecutorListener(env, listener));
+    LuaEngine::resetListener(new ScriptExecutorListener(env, listener));
 
     // Push the function name we want to invoke to Lua stack
     const char* functionNameStr = env->GetStringUTFChars(functionName, nullptr);
-    status = engine->PushFunction(functionNameStr);
+    status = engine->pushFunction(functionNameStr);
     env->ReleaseStringUTFChars(functionName, functionNameStr);
     // status == 1 if the name is indeed a function.
     if (!status) {
@@ -119,10 +118,10 @@
 
     // Unpack bundle in savedState, convert to Lua table and push it to Lua
     // stack.
-    PushBundleToLuaTable(env, engine, savedState);
+    pushBundleToLuaTable(env, engine, savedState);
 
     // Execute the function. This will block until complete or error.
-    if (engine->Run()) {
+    if (engine->run()) {
         env->ThrowNew(env->FindClass("java/lang/RuntimeException"),
                       "Runtime error occurred while running the function.");
         return;
diff --git a/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp b/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp
index 8c10aa4..d80aae8 100644
--- a/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp
+++ b/cpp/telemetry/script_executor/src/ScriptExecutorListener.cpp
@@ -17,7 +17,6 @@
 #include "ScriptExecutorListener.h"
 
 #include <android-base/logging.h>
-#include <android_runtime/AndroidRuntime.h>
 
 namespace android {
 namespace automotive {
@@ -25,14 +24,27 @@
 namespace script_executor {
 
 ScriptExecutorListener::~ScriptExecutorListener() {
-    if (mScriptExecutorListener != NULL) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
+    JNIEnv* env = getCurrentJNIEnv();
+    if (mScriptExecutorListener != nullptr) {
         env->DeleteGlobalRef(mScriptExecutorListener);
     }
 }
 
 ScriptExecutorListener::ScriptExecutorListener(JNIEnv* env, jobject script_executor_listener) {
     mScriptExecutorListener = env->NewGlobalRef(script_executor_listener);
+    env->GetJavaVM(&mJavaVM);
+}
+
+void ScriptExecutorListener::onSuccess(jobject bundle) {
+    JNIEnv* env = getCurrentJNIEnv();
+    if (mScriptExecutorListener == nullptr) {
+        env->FatalError(
+                "mScriptExecutorListener must point to a valid listener object, not nullptr.");
+    }
+    jclass listenerClass = env->GetObjectClass(mScriptExecutorListener);
+    jmethodID onSuccessMethod =
+            env->GetMethodID(listenerClass, "onSuccess", "(Landroid/os/Bundle;)V");
+    env->CallVoidMethod(mScriptExecutorListener, onSuccessMethod, bundle);
 }
 
 void ScriptExecutorListener::onError(const int errorType, const std::string& message,
@@ -41,6 +53,14 @@
               << ", stackTrace: " << stackTrace;
 }
 
+JNIEnv* ScriptExecutorListener::getCurrentJNIEnv() {
+    JNIEnv* env;
+    if (mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOG(FATAL) << "Unable to return JNIEnv from JavaVM";
+    }
+    return env;
+}
+
 }  // namespace script_executor
 }  // namespace telemetry
 }  // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/ScriptExecutorListener.h b/cpp/telemetry/script_executor/src/ScriptExecutorListener.h
index 1e5c7d7..5f6c380 100644
--- a/cpp/telemetry/script_executor/src/ScriptExecutorListener.h
+++ b/cpp/telemetry/script_executor/src/ScriptExecutorListener.h
@@ -35,13 +35,20 @@
 
     void onScriptFinished() {}
 
-    void onSuccess() {}
+    void onSuccess(jobject bundle);
 
     void onError(const int errorType, const std::string& message, const std::string& stackTrace);
 
+    JNIEnv* getCurrentJNIEnv();
+
 private:
     // Stores a jni global reference to Java Script Executor listener object.
     jobject mScriptExecutorListener;
+
+    // Stores JavaVM pointer in order to be able to get JNIEnv pointer.
+    // This is done because JNIEnv cannot be shared between threads.
+    // https://developer.android.com/training/articles/perf-jni.html#javavm-and-jnienv
+    JavaVM* mJavaVM;
 };
 
 }  // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
index 9e2c43a..8cdf87a 100644
--- a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
+++ b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
@@ -44,21 +44,21 @@
 
 JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativePushBundleToLuaTableCaller(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundle) {
-    PushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
+    pushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
                          bundle);
 }
 
 JNIEXPORT jint JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeGetObjectSize(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jint index) {
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
-    return lua_rawlen(engine->GetLuaState(), static_cast<int>(index));
+    return lua_rawlen(engine->getLuaState(), static_cast<int>(index));
 }
 
 JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasBooleanValue(
         JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jboolean value) {
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
@@ -76,7 +76,7 @@
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
     // Assumes the table is on top of the stack.
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
@@ -94,7 +94,7 @@
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
     // Assumes the table is on top of the stack.
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
@@ -112,7 +112,7 @@
     const char* rawKey = env->GetStringUTFChars(key, nullptr);
     LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
     // Assumes the table is on top of the stack.
-    auto* luaState = engine->GetLuaState();
+    auto* luaState = engine->getLuaState();
     lua_pushstring(luaState, rawKey);
     env->ReleaseStringUTFChars(key, rawKey);
     lua_gettable(luaState, -2);
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
index 57d82ca..c9ece21 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
@@ -128,4 +128,12 @@
    * @param actions              List of actions take on resource overusing packages.
    */
    void actionTakenOnResourceOveruse(in List<PackageResourceOveruseAction> actions);
+
+   /**
+    * Enable/disable the internal client health check process.
+    * Disabling would stop the ANR killing process.
+    *
+    * @param isEnabled            New enabled state.
+    */
+    void controlProcessHealthCheck(in boolean disable);
 }
diff --git a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
index 1810c92..e7229ba 100644
--- a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
+++ b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
@@ -291,6 +291,16 @@
         invokeDaemonMethod((daemon) -> daemon.actionTakenOnResourceOveruse(actions));
     }
 
+    /**
+     * Enable/disable the internal client health check process.
+     * Disabling would stop the ANR killing process.
+     *
+     * @param disable True to disable watchdog's health check process.
+     */
+    public void controlProcessHealthCheck(boolean disable) throws RemoteException {
+        invokeDaemonMethod((daemon) -> daemon.controlProcessHealthCheck(disable));
+    }
+
     private void invokeDaemonMethod(Invokable r) throws RemoteException {
         ICarWatchdog daemon;
         synchronized (mLock) {
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.cpp b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
index 6fb6633..96dd6b3 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.cpp
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
@@ -238,6 +238,16 @@
     return {};
 }
 
+bool isSafeToKillAnyPackage(const std::vector<std::string>& packages,
+                            const std::unordered_set<std::string>& safeToKillPackages) {
+    for (const auto& packageName : packages) {
+        if (safeToKillPackages.find(packageName) != safeToKillPackages.end()) {
+            return true;
+        }
+    }
+    return false;
+}
+
 }  // namespace
 
 IoOveruseConfigs::ParseXmlFileFunction IoOveruseConfigs::sParseXmlFile =
@@ -724,11 +734,26 @@
     }
     switch (packageInfo.componentType) {
         case ComponentType::SYSTEM:
-            return mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
-                    mSystemConfig.mSafeToKillPackages.end();
+            if (mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
+                mSystemConfig.mSafeToKillPackages.end()) {
+                return true;
+            }
+            return isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
+                                          mSystemConfig.mSafeToKillPackages);
         case ComponentType::VENDOR:
-            return mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
-                    mVendorConfig.mSafeToKillPackages.end();
+            if (mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
+                mVendorConfig.mSafeToKillPackages.end()) {
+                return true;
+            }
+            /*
+             * Packages under the vendor shared UID may contain system packages because when
+             * CarWatchdogService derives the shared component type it attributes system packages
+             * as vendor packages when there is at least one vendor package.
+             */
+            return isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
+                                          mSystemConfig.mSafeToKillPackages) ||
+                    isSafeToKillAnyPackage(packageInfo.sharedUidPackages,
+                                           mVendorConfig.mSafeToKillPackages);
         default:
             return true;
     }
diff --git a/cpp/watchdog/server/src/PackageInfoResolver.cpp b/cpp/watchdog/server/src/PackageInfoResolver.cpp
index 2b30600..84d7c67 100644
--- a/cpp/watchdog/server/src/PackageInfoResolver.cpp
+++ b/cpp/watchdog/server/src/PackageInfoResolver.cpp
@@ -179,9 +179,23 @@
         if (id.name.empty()) {
             continue;
         }
-        if (const auto it = mPackagesToAppCategories.find(id.name);
-            packageInfo.uidType == UidType::APPLICATION && it != mPackagesToAppCategories.end()) {
-            packageInfo.appCategoryType = it->second;
+        if (packageInfo.uidType == UidType::APPLICATION) {
+            if (const auto it = mPackagesToAppCategories.find(id.name);
+                it != mPackagesToAppCategories.end()) {
+                packageInfo.appCategoryType = it->second;
+            } else if (!packageInfo.sharedUidPackages.empty()) {
+                /* The recommendation for the OEMs is to define the application category mapping
+                 * by the shared package names. However, this a fallback to catch if any mapping is
+                 * defined by the individual package name.
+                 */
+                for (const auto& packageName : packageInfo.sharedUidPackages) {
+                    if (const auto it = mPackagesToAppCategories.find(packageName);
+                        it != mPackagesToAppCategories.end()) {
+                        packageInfo.appCategoryType = it->second;
+                        break;
+                    }
+                }
+            }
         }
         mUidToPackageInfoMapping[id.uid] = packageInfo;
     }
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 6da5fb5..be49ff9 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -268,6 +268,15 @@
     return Status::ok();
 }
 
+Status WatchdogInternalHandler::controlProcessHealthCheck(bool disable) {
+    Status status = checkSystemUser();
+    if (!status.isOk()) {
+        return status;
+    }
+    mWatchdogProcessService->setEnabled(!disable);
+    return Status::ok();
+}
+
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.h b/cpp/watchdog/server/src/WatchdogInternalHandler.h
index a2b4892..e23620e 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.h
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.h
@@ -91,8 +91,9 @@
                     configs) override;
     android::binder::Status actionTakenOnResourceOveruse(
             const std::vector<
-                    android::automotive::watchdog::internal::PackageResourceOveruseAction>&
-                    actions);
+                    android::automotive::watchdog::internal::PackageResourceOveruseAction>& actions)
+            override;
+    android::binder::Status controlProcessHealthCheck(bool disable) override;
 
 protected:
     void terminate() {
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index 97a4047..fca1174 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -83,10 +83,11 @@
 const int32_t MSG_VHAL_WATCHDOG_ALIVE = static_cast<int>(TimeoutLength::TIMEOUT_NORMAL) + 1;
 const int32_t MSG_VHAL_HEALTH_CHECK = MSG_VHAL_WATCHDOG_ALIVE + 1;
 
-// VHAL sends heart beat every 3s. Car watchdog checks if there is the latest heart beat from VHAL
+// TODO(b/193742550): Restore the timeout to 3s after configuration by vendors is added.
+// VHAL sends heart beat every 6s. Car watchdog checks if there is the latest heart beat from VHAL
 // with 1s marginal time.
-constexpr std::chrono::nanoseconds kVhalHealthCheckDelayNs = 4s;
-constexpr int64_t kVhalHeartBeatIntervalMs = 3000;
+constexpr std::chrono::milliseconds kVhalHeartBeatIntervalMs = 6s;
+constexpr std::chrono::nanoseconds kVhalHealthCheckDelayNs = kVhalHeartBeatIntervalMs + 1s;
 
 constexpr const char kServiceName[] = "WatchdogProcessService";
 constexpr const char kVhalInterfaceName[] = "android.hardware.automotive.vehicle@2.0::IVehicle";
@@ -799,7 +800,7 @@
         Mutex::Autolock lock(mMutex);
         lastEventTime = mVhalHeartBeat.eventTime;
     }
-    if (currentUptime > lastEventTime + kVhalHeartBeatIntervalMs) {
+    if (currentUptime > lastEventTime + kVhalHeartBeatIntervalMs.count()) {
         ALOGW("VHAL failed to update heart beat within timeout. Terminating VHAL...");
         terminateVhal();
     }
diff --git a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
index 79b32fc..c03ad85 100644
--- a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
@@ -75,12 +75,14 @@
 
 PackageInfo constructPackageInfo(
         const char* packageName, const ComponentType componentType,
-        const ApplicationCategoryType appCategoryType = ApplicationCategoryType::OTHERS) {
+        const ApplicationCategoryType appCategoryType = ApplicationCategoryType::OTHERS,
+        const std::vector<std::string>& sharedUidPackages = std::vector<std::string>()) {
     PackageInfo packageInfo;
     packageInfo.packageIdentifier.name = packageName;
     packageInfo.uidType = UidType::APPLICATION;
     packageInfo.componentType = componentType;
     packageInfo.appCategoryType = appCategoryType;
+    packageInfo.sharedUidPackages = sharedUidPackages;
     return packageInfo;
 }
 
@@ -832,6 +834,28 @@
     EXPECT_THAT(actual, MEDIA_THRESHOLDS);
 }
 
+TEST_F(IoOveruseConfigsTest, TestFetchThresholdForSharedSystemPackages) {
+    const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+    auto sampleSystemConfig = sampleUpdateSystemConfig();
+    auto& ioConfig = sampleSystemConfig.resourceSpecificConfigurations[0]
+                             .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:systemSharedPackage",
+                                         toPerStateBytes(100, 200, 300)));
+
+    ioOveruseConfigs->update({sampleSystemConfig});
+
+    auto actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("shared:systemSharedPackage", ComponentType::SYSTEM));
+
+    EXPECT_THAT(actual, toPerStateBytes(100, 200, 300));
+
+    actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("systemSharedPackage", ComponentType::SYSTEM));
+
+    EXPECT_THAT(actual, SYSTEM_COMPONENT_LEVEL_THRESHOLDS);
+}
+
 TEST_F(IoOveruseConfigsTest, TestFetchThresholdForVendorPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
 
@@ -853,6 +877,28 @@
     EXPECT_THAT(actual, MAPS_THRESHOLDS);
 }
 
+TEST_F(IoOveruseConfigsTest, TestFetchThresholdForSharedVendorPackages) {
+    const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+    auto sampleVendorConfig = sampleUpdateVendorConfig();
+    auto& ioConfig = sampleVendorConfig.resourceSpecificConfigurations[0]
+                             .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:vendorSharedPackage",
+                                         toPerStateBytes(100, 200, 300)));
+
+    ioOveruseConfigs->update({sampleVendorConfig});
+
+    auto actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("shared:vendorSharedPackage", ComponentType::VENDOR));
+
+    EXPECT_THAT(actual, toPerStateBytes(100, 200, 300));
+
+    actual = ioOveruseConfigs->fetchThreshold(
+            constructPackageInfo("vendorSharedPackage", ComponentType::VENDOR));
+
+    EXPECT_THAT(actual, VENDOR_COMPONENT_LEVEL_THRESHOLDS);
+}
+
 TEST_F(IoOveruseConfigsTest, TestFetchThresholdForThirdPartyPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
 
@@ -883,6 +929,36 @@
             constructPackageInfo("systemPackageA", ComponentType::SYSTEM)));
 }
 
+TEST_F(IoOveruseConfigsTest, TestIsSafeToKillSharedSystemPackages) {
+    auto sampleSystemConfig = sampleUpdateSystemConfig();
+    sampleSystemConfig.safeToKillPackages.push_back("sharedUidSystemPackageC");
+    sampleSystemConfig.safeToKillPackages.push_back("shared:systemSharedPackageD");
+    sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+
+    EXPECT_RESULT_OK(ioOveruseConfigs->update({sampleSystemConfig}));
+
+    PackageInfo packageInfo =
+            constructPackageInfo("systemSharedPackage", ComponentType::SYSTEM,
+                                 ApplicationCategoryType::OTHERS,
+                                 {"sharedUidSystemPackageA", "sharedUidSystemPackageB",
+                                  "sharedUidSystemPackageC"});
+
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when at least one package under shared UID is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("shared:systemSharedPackageD", ComponentType::SYSTEM,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidSystemPackageA"});
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when shared package is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("systemSharedPackageD", ComponentType::SYSTEM,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidSystemPackageA"});
+    EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Shouldn't be safe-to-kill when the 'shared:' prefix is missing";
+}
+
 TEST_F(IoOveruseConfigsTest, TestIsSafeToKillVendorPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
     EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(
@@ -892,6 +968,40 @@
             constructPackageInfo("vendorPackageA", ComponentType::VENDOR)));
 }
 
+TEST_F(IoOveruseConfigsTest, TestIsSafeToKillSharedVendorPackages) {
+    auto sampleVendorConfig = sampleUpdateVendorConfig();
+    sampleVendorConfig.safeToKillPackages.push_back("sharedUidVendorPackageC");
+    sampleVendorConfig.safeToKillPackages.push_back("shared:vendorSharedPackageD");
+
+    auto sampleSystemConfig = sampleUpdateSystemConfig();
+    sampleSystemConfig.safeToKillPackages.push_back("sharedUidSystemPackageC");
+
+    sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+
+    EXPECT_RESULT_OK(ioOveruseConfigs->update({sampleSystemConfig, sampleVendorConfig}));
+
+    PackageInfo packageInfo =
+            constructPackageInfo("vendorSharedPackage", ComponentType::VENDOR,
+                                 ApplicationCategoryType::OTHERS,
+                                 {"sharedUidVendorPackageA", "sharedUidVendorPackageB",
+                                  "sharedUidVendorPackageC"});
+
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when at least one package under shared UID is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("shared:vendorSharedPackageD", ComponentType::VENDOR,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidVendorPackageA"});
+    EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Should be safe-to-kill when shared package is safe-to-kill";
+
+    packageInfo =
+            constructPackageInfo("shared:vendorSharedPackageE", ComponentType::VENDOR,
+                                 ApplicationCategoryType::OTHERS, {"sharedUidVendorPackageA"});
+    EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(packageInfo))
+            << "Shouldn't be safe-to-kill when the 'shared:' prefix is missing";
+}
+
 TEST_F(IoOveruseConfigsTest, TestIsSafeToKillThirdPartyPackages) {
     const auto ioOveruseConfigs = sampleIoOveruseConfigs();
     EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(
@@ -931,6 +1041,32 @@
                 UnorderedElementsAre("vendorPackage", "vendorPkgB"));
 }
 
+TEST_F(IoOveruseConfigsTest, TestVendorPackagePrefixesWithSharedPackages) {
+    auto sampleVendorConfig = sampleUpdateVendorConfig();
+    sampleVendorConfig.vendorPackagePrefixes.push_back("shared:vendorSharedPackage");
+    sampleVendorConfig.safeToKillPackages.push_back("sharedUidVendorPackageD");
+    sampleVendorConfig.safeToKillPackages.push_back("shared:vendorSharedPackageE");
+    sampleVendorConfig.safeToKillPackages.push_back("shared:vndrSharedPkgF");
+
+    auto& ioConfig = sampleVendorConfig.resourceSpecificConfigurations[0]
+                             .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:vendorSharedPackageG",
+                                         VENDOR_PACKAGE_A_THRESHOLDS));
+    ioConfig.packageSpecificThresholds.push_back(
+            toPerStateIoOveruseThreshold("shared:vndrSharedPkgH", VENDOR_PACKAGE_A_THRESHOLDS));
+
+    sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+
+    EXPECT_RESULT_OK(ioOveruseConfigs->update({sampleVendorConfig}));
+
+    EXPECT_THAT(ioOveruseConfigs->vendorPackagePrefixes(),
+                UnorderedElementsAre("vendorPackage", "vendorPkgB", "shared:vendorSharedPackage",
+                                     "sharedUidVendorPackageD", "shared:vndrSharedPkgF",
+                                     "shared:vndrSharedPkgH"));
+}
+
 TEST_F(IoOveruseConfigsTest, TestPackagesToAppCategoriesWithSystemConfig) {
     IoOveruseConfigs ioOveruseConfigs;
     const auto resourceOveruseConfig = sampleUpdateSystemConfig();
diff --git a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
index f2fe3a6..cf282be 100644
--- a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
+++ b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
@@ -195,6 +195,8 @@
             // system.package.B is native package so this should be ignored.
             {"system.package.B", ApplicationCategoryType::MAPS},
             {"vendor.package.A", ApplicationCategoryType::MEDIA},
+            {"shared:vendor.package.C", ApplicationCategoryType::MEDIA},
+            {"vendor.package.shared.uid.D", ApplicationCategoryType::MAPS},
     };
     peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
     /*
@@ -213,23 +215,38 @@
                                   ApplicationCategoryType::OTHERS)},
             {15100,
              constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
-                                  ComponentType::VENDOR, ApplicationCategoryType::MEDIA)},
+                                  ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
             {16700,
              constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
                                   ApplicationCategoryType::OTHERS)},
+            {18100,
+             constructPackageInfo("shared:vendor.package.C", 18100, UidType::APPLICATION,
+                                  ComponentType::VENDOR, ApplicationCategoryType::OTHERS)},
+            {19100,
+             constructPackageInfo("shared:vendor.package.D", 19100, UidType::APPLICATION,
+                                  ComponentType::VENDOR, ApplicationCategoryType::OTHERS,
+                                  {"vendor.package.shared.uid.D"})},
     };
 
-    std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700};
+    std::vector<int32_t> expectedUids = {6100, 7700, 15100, 16700, 18100, 19100};
     std::vector<std::string> expectedPrefixes = {"vendor.pkg"};
     std::vector<PackageInfo> injectPackageInfos = {expectedMappings.at(6100),
                                                    expectedMappings.at(7700),
                                                    expectedMappings.at(15100),
-                                                   expectedMappings.at(16700)};
+                                                   expectedMappings.at(16700),
+                                                   expectedMappings.at(18100),
+                                                   expectedMappings.at(19100)};
+
+    expectedMappings.at(15100).appCategoryType = ApplicationCategoryType::MEDIA;
+    expectedMappings.at(18100).appCategoryType = ApplicationCategoryType::MEDIA;
+    expectedMappings.at(19100).appCategoryType = ApplicationCategoryType::MAPS;
+
     EXPECT_CALL(*peer.mockWatchdogServiceHelper,
                 getPackageInfosForUids(expectedUids, expectedPrefixes, _))
             .WillOnce(DoAll(SetArgPointee<2>(injectPackageInfos), Return(binder::Status::ok())));
 
-    auto actualMappings = packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700});
+    auto actualMappings =
+            packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700, 18100, 19100});
 
     EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
             << "Expected: " << toString(expectedMappings)
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index efa9eef..4646a11 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -470,6 +470,19 @@
     ASSERT_FALSE(status.isOk()) << status;
 }
 
+TEST_F(WatchdogInternalHandlerTest, TestControlProcessHealthCheck) {
+    setSystemCallingUid();
+    EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/true)).Times(1);
+    Status status = mWatchdogInternalHandler->controlProcessHealthCheck(false);
+    ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestErrorOnControlProcessHealthCheckWithNonSystemCallingUid) {
+    EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
+    Status status = mWatchdogInternalHandler->controlProcessHealthCheck(false);
+    ASSERT_FALSE(status.isOk()) << status;
+}
+
 }  // namespace watchdog
 }  // namespace automotive
 }  // namespace android
diff --git a/service/Android.bp b/service/Android.bp
index 709c928..b2456d1 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -34,6 +34,7 @@
 ]
 
 common_lib_deps = [
+    "android.automotive.telemetry.internal-java",  // ICarTelemetryInternal
     "android.car.cluster.navigation",
     "android.car.userlib",
     "android.car.watchdoglib",
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index b587127..6703b61 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -50,7 +50,7 @@
     <string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"કારમાં કોઈ અન્ય ઑડિયો વગાડવાને કારણે જો કોઈ ઍપનું વૉલ્યૂમ ઘટાડવામાં આવતું હોય, તો ઍપને સૂચિત કરવાની મંજૂરી આપવામાં આવે છે."</string>
     <string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"આંતરિક પરીક્ષણ હેતુથી તમારી કારના HALનું અનુસરણ કરો."</string>
     <string name="car_permission_desc_audio_volume" msgid="536626185654307889">"તમારી કારના ઑડિયોનું વૉલ્યૂમ નિયંત્રિત કરવાની મંજૂરી આપો."</string>
-    <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"તમારી કારના ઑડિઓ સેટિંગ્સ નિયંત્રિત કરો."</string>
+    <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"તમારી કારના ઑડિયો સેટિંગ નિયંત્રિત કરો."</string>
     <string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"ઍપ્લિકેશન બ્લૉકિંગ"</string>
     <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"ડ્રાઇવિંગ કરતી વખતે ઍપ્લિકેશન બ્લૉકિંગ નિયંત્રિત કરો."</string>
     <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"નૅવિગેશન મેનેજર"</string>
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 8cee561..1f6375e 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.hardware.power.CarPowerPolicy;
@@ -60,6 +61,7 @@
 import android.os.UserManager;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
+import android.util.DebugUtils;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Slog;
@@ -68,6 +70,7 @@
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.utils.Slogf;
 
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -76,6 +79,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.stream.Collectors;
 
 /**
@@ -87,7 +91,9 @@
  * it were being browsed only. However, that source is still considered the active source, and
  * should be the source displayed in any Media related UIs (Media Center, home screen, etc).
  */
-public class CarMediaService extends ICarMedia.Stub implements CarServiceBase {
+public final class CarMediaService extends ICarMedia.Stub implements CarServiceBase {
+
+    private static final boolean DEBUG = false;
 
     private static final String SOURCE_KEY = "media_source_component";
     private static final String SOURCE_KEY_SEPARATOR = "_";
@@ -96,6 +102,7 @@
     private static final String COMPONENT_NAME_SEPARATOR = ",";
     private static final String MEDIA_CONNECTION_ACTION = "com.android.car.media.MEDIA_CONNECTION";
     private static final String EXTRA_AUTOPLAY = "com.android.car.media.autoplay";
+    private static final String LAST_UPDATE_KEY = "last_update";
 
     private static final int MEDIA_SOURCE_MODES = 2;
 
@@ -126,6 +133,8 @@
     private boolean mWasPreviouslyDisabledByPowerPolicy;
     @GuardedBy("mLock")
     private boolean mWasPlayingBeforeDisabled;
+
+    // NOTE: must use getSharedPrefsForWriting() to write to it
     private SharedPreferences mSharedPrefs;
     private SessionChangedListener mSessionsListener;
     private int mPlayOnMediaSourceChangedConfig;
@@ -151,6 +160,7 @@
     private ComponentName[] mRemovedMediaSourceComponents = new ComponentName[MEDIA_SOURCE_MODES];
 
     private final IntentFilter mPackageUpdateFilter;
+    @GuardedBy("mLock")
     private boolean mIsPackageUpdateReceiverRegistered;
 
     /**
@@ -230,7 +240,7 @@
                 maybeInitUser(event.getUserId());
                 break;
             case CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED:
-                onUserUnlock(event.getUserId());
+                onUserUnlocked(event.getUserId());
                 break;
         }
     };
@@ -309,8 +319,9 @@
     @Override
     // This method is called from ICarImpl after CarMediaService is created.
     public void init() {
-        int currentUser = ActivityManager.getCurrentUser();
-        maybeInitUser(currentUser);
+        int currentUserId = ActivityManager.getCurrentUser();
+        Slog.d(CarLog.TAG_MEDIA, "init(): currentUser=" + currentUserId);
+        maybeInitUser(currentUserId);
         setPowerPolicyListener();
     }
 
@@ -325,21 +336,16 @@
         }
     }
 
-    private void initUser(int userId) {
-        // SharedPreferences are shared among different users thus only need initialized once. And
-        // they should be initialized after user 0 is unlocked because SharedPreferences in
-        // credential encrypted storage are not available until after user 0 is unlocked.
-        // initUser() is called when the current foreground user is unlocked, and by that time user
-        // 0 has been unlocked already, so initializing SharedPreferences in initUser() is fine.
-        synchronized (mLock) {
-            if (mSharedPrefs == null) {
-                mSharedPrefs = mContext.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
-            }
+    private void initUser(@UserIdInt int userId) {
+        Slog.d(CarLog.TAG_MEDIA, "initUser(): userId=" + userId + ", mSharedPrefs=" + mSharedPrefs);
+        UserHandle currentUser = new UserHandle(userId);
 
+        maybeInitSharedPrefs(userId);
+
+        synchronized (mLock) {
             if (mIsPackageUpdateReceiverRegistered) {
                 mContext.unregisterReceiver(mPackageUpdateReceiver);
             }
-            UserHandle currentUser = new UserHandle(userId);
             mContext.registerReceiverAsUser(mPackageUpdateReceiver, currentUser,
                     mPackageUpdateFilter, null, null);
             mIsPackageUpdateReceiverRegistered = true;
@@ -358,6 +364,30 @@
         }
     }
 
+    private void maybeInitSharedPrefs(@UserIdInt int userId) {
+        // SharedPreferences are shared among different users thus only need initialized once. And
+        // they should be initialized after user 0 is unlocked because SharedPreferences in
+        // credential encrypted storage are not available until after user 0 is unlocked.
+        // initUser() is called when the current foreground user is unlocked, and by that time user
+        // 0 has been unlocked already, so initializing SharedPreferences in initUser() is fine.
+        if (mSharedPrefs != null) {
+            Slog.i(CarLog.TAG_MEDIA, "Shared preferences already set (on directory "
+                    + mContext.getDataDir() + ") when initializing user " + userId);
+            return;
+        }
+        Slog.i(CarLog.TAG_MEDIA, "Getting shared preferences when initializing user "
+                + userId);
+        mSharedPrefs = mContext.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
+
+        // Try to access the properties to make sure they were properly open
+        if (DEBUG) {
+            Slogf.i(CarLog.TAG_MEDIA, "Number of prefs: %d", mSharedPrefs.getAll().size());
+
+        } else if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
+            Slogf.d(CarLog.TAG_MEDIA, "Number of prefs: %d", mSharedPrefs.getAll().size());
+        }
+    }
+
     /**
      * Starts a service on the current user that binds to the media browser of the current media
      * source. We start a new service because this one runs on user 0, and MediaBrowser doesn't
@@ -373,20 +403,19 @@
     }
 
     private boolean sharedPrefsInitialized() {
-        if (mSharedPrefs == null) {
-            // It shouldn't reach this but let's be cautious.
-            Slog.e(CarLog.TAG_MEDIA, "SharedPreferences are not initialized!");
-            String className = getClass().getName();
-            for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
-                // Let's print the useful logs only.
-                String log = ste.toString();
-                if (log.contains(className)) {
-                    Slog.e(CarLog.TAG_MEDIA, log);
-                }
+        if (mSharedPrefs != null) return true;
+
+        // It shouldn't reach this but let's be cautious.
+        Slog.e(CarLog.TAG_MEDIA, "SharedPreferences are not initialized!");
+        String className = getClass().getName();
+        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
+            // Let's print the useful logs only.
+            String log = ste.toString();
+            if (log.contains(className)) {
+                Slog.e(CarLog.TAG_MEDIA, log);
             }
-            return false;
         }
-        return true;
+        return false;
     }
 
     private boolean isCurrentUserEphemeral() {
@@ -414,43 +443,85 @@
 
     @Override
     public void dump(IndentingPrintWriter writer) {
+        writer.println("*CarMediaService*");
+        writer.increaseIndent();
+
+        writer.printf("Pending init: %b\n", mPendingInit);
+        boolean hasSharedPrefs;
         synchronized (mLock) {
-            writer.println("*CarMediaService*");
-            writer.increaseIndent();
-            writer.printf("Current playback media component: %s\n",
-                    mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] == null ? "-"
-                    : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK].flattenToString());
-            writer.printf("Current browse media component: %s\n",
-                    mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE] == null ? "-"
-                    : mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE].flattenToString());
+            hasSharedPrefs = mSharedPrefs != null;
+            dumpCurrentMediaComponent(writer, "playback", MEDIA_SOURCE_MODE_PLAYBACK);
+            dumpCurrentMediaComponent(writer, "browse", MEDIA_SOURCE_MODE_BROWSE);
             if (mActiveUserMediaController != null) {
                 writer.printf("Current media controller: %s\n",
                         mActiveUserMediaController.getPackageName());
                 writer.printf("Current browse service extra: %s\n",
                         getClassName(mActiveUserMediaController));
+            } else {
+                writer.println("no active user media controller");
             }
-            writer.printf("Number of active media sessions: %s\n", mMediaSessionManager
-                    .getActiveSessionsForUser(null,
-                            new UserHandle(ActivityManager.getCurrentUser())).size());
+            int userId = ActivityManager.getCurrentUser();
+            writer.printf("Number of active media sessions (for current user %d): %d\n", userId,
+                    mMediaSessionManager.getActiveSessionsForUser(/* notificationListener= */ null,
+                            new UserHandle(userId)).size());
 
-            writer.println("Playback media source history:");
-            writer.increaseIndent();
-            for (ComponentName name : getLastMediaSources(MEDIA_SOURCE_MODE_PLAYBACK)) {
-                writer.println(name.flattenToString());
-            }
-            writer.decreaseIndent();
-            writer.println("Browse media source history:");
-            writer.increaseIndent();
-            for (ComponentName name : getLastMediaSources(MEDIA_SOURCE_MODE_BROWSE)) {
-                writer.println(name.flattenToString());
-            }
-            writer.decreaseIndent();
             writer.printf("Disabled by power policy: %s\n", mIsDisabledByPowerPolicy);
             if (mIsDisabledByPowerPolicy) {
                 writer.printf("Before being disabled by power policy, audio was %s\n",
                         mWasPlayingBeforeDisabled ? "active" : "inactive");
             }
         }
+
+        if (hasSharedPrefs) {
+            dumpLastMediaSources(writer, "Playback", MEDIA_SOURCE_MODE_PLAYBACK);
+            dumpLastMediaSources(writer, "Browse", MEDIA_SOURCE_MODE_BROWSE);
+            dumpSharedPrefs(writer);
+        } else {
+            writer.println("No shared preferences");
+        }
+
+        writer.decreaseIndent();
+    }
+
+    private void dumpCurrentMediaComponent(IndentingPrintWriter writer, String name,
+            @CarMediaManager.MediaSourceMode int mode) {
+        ComponentName componentName = mPrimaryMediaComponents[mode];
+        writer.printf("Current %s media component: %s\n", name, componentName == null
+                ? "-"
+                : componentName.flattenToString());
+    }
+
+    private void dumpLastMediaSources(IndentingPrintWriter writer, String name,
+            @CarMediaManager.MediaSourceMode int mode) {
+        writer.printf("%s media source history:\n", name);
+        writer.increaseIndent();
+        List<ComponentName> lastMediaSources = getLastMediaSources(mode);
+        for (int i = 0; i < lastMediaSources.size(); i++) {
+            ComponentName componentName = lastMediaSources.get(i);
+            if (componentName == null) {
+                Slogf.e(CarLog.TAG_MEDIA, "dump(): empty last media source of %s at index %d: %s",
+                        mediaModeToString(mode), i, lastMediaSources);
+                continue;
+            }
+            writer.println(componentName.flattenToString());
+        }
+        writer.decreaseIndent();
+    }
+
+    private void dumpSharedPrefs(IndentingPrintWriter writer) {
+        Map<String, ?> allPrefs = mSharedPrefs.getAll();
+        writer.printf("%d shared preferences (saved on directory %s)",
+                allPrefs.size(), mContext.getDataDir());
+        if (!Log.isLoggable(CarLog.TAG_MEDIA, Log.VERBOSE) || allPrefs.isEmpty()) {
+            writer.println();
+            return;
+        }
+        writer.println(':');
+        writer.increaseIndent();
+        for (Entry<String, ?> pref : allPrefs.entrySet()) {
+            writer.printf("%s = %s\n", pref.getKey(), pref.getValue());
+        }
+        writer.decreaseIndent();
     }
 
     /**
@@ -531,10 +602,12 @@
     }
 
     // TODO(b/153115826): this method was used to be called from the ICar binder thread, but it's
-    // now called by UserCarService. Currently UserCarServie is calling every listener in one
+    // now called by UserCarService. Currently UserCarService is calling every listener in one
     // non-main thread, but it's not clear how the final behavior will be. So, for now it's ok
     // to post it to mMainHandler, but once b/145689885 is fixed, we might not need it.
-    private void onUserUnlock(int userId) {
+    private void onUserUnlocked(@UserIdInt int userId) {
+        Slog.d(CarLog.TAG_MEDIA, "onUserUnlocked(): userId=" + userId
+                + ", mPendingInit=" + mPendingInit);
         mMainHandler.post(() -> {
             // No need to handle system user, non current foreground user.
             if (userId == UserHandle.USER_SYSTEM
@@ -904,13 +977,28 @@
         String componentName = component.flattenToString();
         String key = getMediaSourceKey(mode);
         String serialized = mSharedPrefs.getString(key, null);
+        String modeName = null;
+        boolean debug = DEBUG || Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG);
+        if (debug) {
+            modeName = mediaModeToString(mode);
+        }
+
         if (serialized == null) {
-            mSharedPrefs.edit().putString(key, componentName).apply();
+            if (debug) {
+                Slogf.d(CarLog.TAG_MEDIA, "saveLastMediaSource(%s, %s): no value for key %s",
+                        componentName, modeName, key);
+            }
+            getSharedPrefsForWriting().putString(key, componentName).apply();
         } else {
             Deque<String> componentNames = new ArrayDeque<>(getComponentNameList(serialized));
             componentNames.remove(componentName);
             componentNames.addFirst(componentName);
-            mSharedPrefs.edit().putString(key, serializeComponentNameList(componentNames)).apply();
+            String newSerialized = serializeComponentNameList(componentNames);
+            if (debug) {
+                Slogf.d(CarLog.TAG_MEDIA, "saveLastMediaSource(%s, %s): updating %s from %s to %s",
+                        componentName, modeName,  key, serialized, newSerialized);
+            }
+            getSharedPrefsForWriting().putString(key, newSerialized).apply();
         }
     }
 
@@ -960,7 +1048,8 @@
             mCurrentPlaybackState = state;
         }
         String key = getPlaybackStateKey();
-        mSharedPrefs.edit().putInt(key, state).apply();
+        Slogf.d(CarLog.TAG_MEDIA, "savePlaybackState(): %s = %d)", key, state);
+        getSharedPrefsForWriting().putInt(key, state).apply();
     }
 
     /**
@@ -1031,6 +1120,15 @@
         }
     }
 
+    /**
+     * Gets the editor used to update shared preferences.
+     */
+    private SharedPreferences.Editor getSharedPrefsForWriting() {
+        long now = System.currentTimeMillis();
+        Slogf.i(CarLog.TAG_MEDIA, "Updating %s to %d", LAST_UPDATE_KEY, now);
+        return mSharedPrefs.edit().putLong(LAST_UPDATE_KEY, now);
+    }
+
     @NonNull
     private static String getClassName(@NonNull MediaController controller) {
         Bundle sessionExtras = controller.getExtras();
@@ -1039,4 +1137,8 @@
                         Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION);
         return value != null ? value : "";
     }
+
+    private static String mediaModeToString(@CarMediaManager.MediaSourceMode int mode) {
+        return DebugUtils.constantToString(CarMediaManager.class, "MEDIA_SOURCE_", mode);
+    }
 }
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index bad6b71..576aad2 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -18,6 +18,7 @@
 import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
 import static android.car.Car.PERMISSION_CAR_POWER;
 import static android.car.Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG;
+import static android.car.Car.PERMISSION_USE_CAR_WATCHDOG;
 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER;
 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS;
 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER;
@@ -197,6 +198,8 @@
             "watchdog-io-set-3p-foreground-bytes";
     private static final String COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES =
             "watchdog-io-get-3p-foreground-bytes";
+    private static final String COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK =
+            "watchdog-control-health-check";
 
     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
             android.Manifest.permission.CREATE_USERS,
@@ -269,6 +272,8 @@
                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
         USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES,
                 PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG);
+        USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK,
+                PERMISSION_USE_CAR_WATCHDOG);
     }
 
     private static final String PARAM_DAY_MODE = "day";
@@ -612,6 +617,10 @@
 
         pw.printf("\t%s\n", COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES);
         pw.println("\t  Gets third-party apps foreground I/O overuse threshold");
+
+        pw.printf("\t%s true|false\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
+        pw.println("\t  Enables/disables car watchdog process health check.");
+        pw.println("\t  Set to true to disable the process health check.");
     }
 
     private static int showInvalidArguments(IndentingPrintWriter pw) {
@@ -940,7 +949,9 @@
             case COMMAND_WATCHDOG_IO_GET_3P_FOREGROUND_BYTES:
                 getWatchdogIoThirdPartyForegroundBytes(writer);
                 break;
-
+            case COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK:
+                controlWatchdogProcessHealthCheck(args, writer);
+                break;
             default:
                 writer.println("Unknown command: \"" + cmd + "\"");
                 showHelp(writer);
@@ -2200,6 +2211,19 @@
                 .setIoOveruseConfiguration(configuration.getIoOveruseConfiguration());
     }
 
+    private void controlWatchdogProcessHealthCheck(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+        boolean newState = Boolean.parseBoolean(args[1]);
+        if (!newState && !args[1].equalsIgnoreCase("false")) {
+            writer.println("Failed to parse argument. Valid arguments: true | false");
+            return;
+        }
+        mCarWatchdogService.controlProcessHealthCheck(newState);
+    }
+
     // Check if the given property is global
     private static boolean isPropertyAreaTypeGlobal(@Nullable String property) {
         if (property == null) {
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index 5de5a81..726f34f 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -39,6 +39,7 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -86,8 +87,8 @@
     public static final int NO_AREA = -1;
     public static final float NO_SAMPLE_RATE = -1;
 
-    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
-            VehicleHal.class.getSimpleName());
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
     private final PowerHalService mPowerHal;
     private final PropertyHalService mPropertyHal;
     private final InputHalService mInputHal;
@@ -124,6 +125,9 @@
      * both passed as parameters.
      */
     public VehicleHal(Context context, IVehicle vehicle) {
+        mHandlerThread = CarServiceUtils.getHandlerThread(
+                VehicleHal.class.getSimpleName());
+        mHandler = new Handler(mHandlerThread.getLooper());
         mPowerHal = new PowerHalService(this);
         mPropertyHal = new PropertyHalService(this);
         mInputHal = new InputHalService(this);
@@ -156,7 +160,10 @@
             UserHalService userHal,
             DiagnosticHalService diagnosticHal,
             ClusterHalService clusterHalService,
-            HalClient halClient) {
+            HalClient halClient,
+            HandlerThread handlerThread) {
+        mHandlerThread = handlerThread;
+        mHandler = new Handler(mHandlerThread.getLooper());
         mPowerHal = powerHal;
         mPropertyHal = propertyHal;
         mInputHal = inputHal;
@@ -581,6 +588,7 @@
 
     private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<>();
 
+    // should be posted to the mHandlerThread
     @Override
     public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
         synchronized (mLock) {
@@ -614,6 +622,7 @@
         // No need to handle on-property-set events in HAL service yet.
     }
 
+    // should be posted to the mHandlerThread
     @Override
     public void onPropertySetError(@CarPropertyManager.CarSetPropertyErrorCode int errorCode,
             int propId, int areaId) {
@@ -800,7 +809,7 @@
         }
         // update timestamp
         v.timestamp = SystemClock.elapsedRealtimeNanos() + TimeUnit.SECONDS.toNanos(delayTime);
-        onPropertyEvent(Lists.newArrayList(v));
+        mHandler.post(() -> onPropertyEvent(Lists.newArrayList(v)));
     }
 
     /**
@@ -838,7 +847,7 @@
                     // Avoid the fake events be covered by real Event
                     v.timestamp = SystemClock.elapsedRealtimeNanos()
                             + TimeUnit.SECONDS.toNanos(timeDurationInSec);
-                    onPropertyEvent(Lists.newArrayList(v));
+                    mHandler.post(() -> onPropertyEvent(Lists.newArrayList(v)));
                 }
             }
         }, /* delay= */0, period);
diff --git a/service/src/com/android/car/telemetry/databroker/DataBroker.java b/service/src/com/android/car/telemetry/databroker/DataBroker.java
index 120c95f..f22a8ca 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBroker.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBroker.java
@@ -22,6 +22,18 @@
 public interface DataBroker {
 
     /**
+     * Interface for receiving notification that script finished.
+     */
+    interface ScriptFinishedCallback {
+        /**
+         * Listens to script finished event.
+         *
+         * @param configName the name of the config whose script finished.
+         */
+        void onScriptFinished(String configName);
+    }
+
+    /**
      * Adds an active {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} that is pending
      * execution. When updating the MetricsConfig to a newer version, the caller must call
      * {@link #removeMetricsConfiguration(TelemetryProto.MetricsConfig)} first to clear the old
@@ -58,7 +70,7 @@
      *
      * @param callback script finished callback.
      */
-    void setOnScriptFinishedCallback(DataBrokerController.ScriptFinishedCallback callback);
+    void setOnScriptFinishedCallback(ScriptFinishedCallback callback);
 
     /**
      * Sets the priority which affects which subscribers can consume data. Invoked by controller to
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
index 7663667..a5fa1cb 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
@@ -34,18 +34,6 @@
     private final DataBroker mDataBroker;
     private final SystemMonitor mSystemMonitor;
 
-    /**
-     * Interface for receiving notification that script finished.
-     */
-    public interface ScriptFinishedCallback {
-        /**
-         * Listens to script finished event.
-         *
-         * @param configName the name of the config whose script finished.
-         */
-        void onScriptFinished(String configName);
-    }
-
     public DataBrokerController(DataBroker dataBroker, SystemMonitor systemMonitor) {
         mDataBroker = dataBroker;
         mDataBroker.setOnScriptFinishedCallback(this::onScriptFinished);
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
index e9549b1..7ac7cf8 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -32,6 +32,7 @@
 import com.android.car.telemetry.TelemetryProto.MetricsConfig;
 import com.android.car.telemetry.publisher.AbstractPublisher;
 import com.android.car.telemetry.publisher.PublisherFactory;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.ref.WeakReference;
@@ -52,8 +53,9 @@
     @VisibleForTesting
     static final int MSG_HANDLE_TASK = 1;
 
+    private final Object mLock = new Object();
     private final HandlerThread mWorkerThread = CarServiceUtils.getHandlerThread(
-            CarTelemetryService.class.getClass().getSimpleName());
+            CarTelemetryService.class.getSimpleName());
     private final Handler mWorkerHandler = new TaskHandler(mWorkerThread.getLooper());
 
     /** Thread-safe int to determine which data can be processed. */
@@ -74,10 +76,10 @@
      * Maps MetricsConfig's name to its subscriptions. This map is useful when removing a
      * MetricsConfig.
      */
+    @GuardedBy("mLock")
     private final Map<String, List<DataSubscriber>> mSubscriptionMap = new ArrayMap<>();
-    private final Object mPublisherLock = new Object();
     private final PublisherFactory mPublisherFactory;
-    private DataBrokerController.ScriptFinishedCallback mScriptFinishedCallback;
+    private ScriptFinishedCallback mScriptFinishedCallback;
 
     public DataBrokerImpl(PublisherFactory publisherFactory) {
         mPublisherFactory = publisherFactory;
@@ -95,9 +97,11 @@
             throw new RuntimeException(
                     "addMetricsConfigurationOnHandlerThread is not called from handler thread");
         }
-        // if metricsConfig already exists, it should not be added again
-        if (mSubscriptionMap.containsKey(metricsConfig.getName())) {
-            return;
+        synchronized (mLock) {
+            // if metricsConfig already exists, it should not be added again
+            if (mSubscriptionMap.containsKey(metricsConfig.getName())) {
+                return;
+            }
         }
         // Create the subscribers for this metrics configuration
         List<DataSubscriber> dataSubscribers = new ArrayList<>(
@@ -106,7 +110,6 @@
             // protobuf publisher to a concrete Publisher
             AbstractPublisher publisher = mPublisherFactory.getPublisher(
                     subscriber.getPublisher().getPublisherCase());
-
             // create DataSubscriber from TelemetryProto.Subscriber
             DataSubscriber dataSubscriber = new DataSubscriber(
                     this,
@@ -118,15 +121,15 @@
             try {
                 // The publisher will start sending data to the subscriber.
                 // TODO(b/191378559): handle bad configs
-                synchronized (mPublisherLock) {
-                    publisher.addDataSubscriber(dataSubscriber);
-                }
+                publisher.addDataSubscriber(dataSubscriber);
             } catch (IllegalArgumentException e) {
                 Slog.w(CarLog.TAG_TELEMETRY, "Invalid config", e);
                 return;
             }
         }
-        mSubscriptionMap.put(metricsConfig.getName(), dataSubscribers);
+        synchronized (mLock) {
+            mSubscriptionMap.put(metricsConfig.getName(), dataSubscribers);
+        }
     }
 
     @Override
@@ -141,25 +144,33 @@
             throw new RuntimeException(
                     "removeMetricsConfigurationOnHandlerThread is not called from handler thread");
         }
-        if (!mSubscriptionMap.containsKey(metricsConfig.getName())) {
-            return;
+        synchronized (mLock) {
+            if (!mSubscriptionMap.containsKey(metricsConfig.getName())) {
+                return;
+            }
         }
         // get the subscriptions associated with this MetricsConfig, remove it from the map
-        List<DataSubscriber> dataSubscribers = mSubscriptionMap.remove(metricsConfig.getName());
+        List<DataSubscriber> dataSubscribers;
+        synchronized (mLock) {
+            dataSubscribers = mSubscriptionMap.remove(metricsConfig.getName());
+        }
         // for each subscriber, remove it from publishers
         for (DataSubscriber subscriber : dataSubscribers) {
             AbstractPublisher publisher = mPublisherFactory.getPublisher(
                     subscriber.getPublisherParam().getPublisherCase());
             try {
-                synchronized (mPublisherLock) {
-                    publisher.removeDataSubscriber(subscriber);
-                }
+                publisher.removeDataSubscriber(subscriber);
             } catch (IllegalArgumentException e) {
                 // It shouldn't happen, but if happens, let's just log it.
                 Slog.w(CarLog.TAG_TELEMETRY, "Failed to remove subscriber from publisher", e);
             }
-            // TODO(b/187743369): remove related tasks from the queue
         }
+        // Remove all the tasks associated with this metrics config. The underlying impl uses the
+        // weakly consistent iterator, which is thread-safe but does not freeze the collection while
+        // iterating, so it may or may not reflect any updates since the iterator was created.
+        // But since adding & polling from queue should happen in the same thread, the task queue
+        // should not be changed while tasks are being iterated and removed.
+        mTaskQueue.removeIf(task -> task.isAssociatedWithMetricsConfig(metricsConfig));
     }
 
     @Override
@@ -187,7 +198,7 @@
     }
 
     @Override
-    public void setOnScriptFinishedCallback(DataBrokerController.ScriptFinishedCallback callback) {
+    public void setOnScriptFinishedCallback(ScriptFinishedCallback callback) {
         // TODO(b/187743369): move the interface on databroker surface and pass it in constructor
         mScriptFinishedCallback = callback;
     }
@@ -200,7 +211,9 @@
 
     @VisibleForTesting
     Map<String, List<DataSubscriber>> getSubscriptionMap() {
-        return mSubscriptionMap;
+        synchronized (mLock) {
+            return new ArrayMap<>((ArrayMap<String, List<DataSubscriber>>) mSubscriptionMap);
+        }
     }
 
     @VisibleForTesting
diff --git a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
index 92f51ba..91b17eb 100644
--- a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
+++ b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
@@ -18,6 +18,8 @@
 
 import android.os.Bundle;
 
+import com.android.car.telemetry.TelemetryProto;
+
 /**
  * A wrapper class containing all the necessary information to invoke the ScriptExecutor API. It
  * is enqueued into the priority queue where it pends execution by {@link DataBroker}.
@@ -44,6 +46,14 @@
         return mTimestampMillis;
     }
 
+    /**
+     * Indicates whether the task is associated with the given
+     * {@link com.android.car.telemetry.TelemetryProto.MetricsConfig).
+     */
+    public boolean isAssociatedWithMetricsConfig(TelemetryProto.MetricsConfig metricsConfig) {
+        return mSubscriber.getMetricsConfig().equals(metricsConfig);
+    }
+
     @Override
     public int compareTo(ScriptExecutionTask other) {
         if (getPriority() < other.getPriority()) {
diff --git a/service/src/com/android/car/telemetry/proto/telemetry.proto b/service/src/com/android/car/telemetry/proto/telemetry.proto
index 5787d62..870a00e 100644
--- a/service/src/com/android/car/telemetry/proto/telemetry.proto
+++ b/service/src/com/android/car/telemetry/proto/telemetry.proto
@@ -38,8 +38,8 @@
   optional int32 version = 2;
 
   // Required.
-  // A script that is executed in devices. Must contain all the handler functions
-  // defined in the listeners below.
+  // A script that is executed at the device side. Must contain all the handler
+  // functions defined in the listeners below.
   // The script functions must be `pure` functions.
   optional string script = 3;
 
@@ -60,19 +60,33 @@
   optional float read_rate = 2;
 }
 
+// Parameters for cartelemetryd publisher.
+// See packages/services/Car/cpp/telemetry for CarData proto and docs.
+message CarTelemetrydPublisher {
+  // Required.
+  // CarData id to subscribe to.
+  // See packages/services/Car/cpp/telemetry/proto/CarData.proto for all the
+  // messages and IDs.
+  optional int32 id = 1;
+}
+
 // Specifies data publisher and its parameters.
 message Publisher {
   oneof publisher {
     VehiclePropertyPublisher vehicle_property = 1;
+    CarTelemetrydPublisher cartelemetryd = 2;
   }
 }
 
 // Specifies publisher with its parameters and the handler function that's invoked
 // when data is received. The format of the data depends on the Publisher.
 message Subscriber {
-  // Name of the script function that's invoked when this subscriber is triggered.
+  // Required.
+  // Name of the function that handles the published data. Must be defined
+  // in the script.
   optional string handler = 1;
 
-  // Publisher and its parameters.
+  // Required.
+  // Publisher definition.
   optional Publisher publisher = 2;
 }
diff --git a/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java b/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
index 1a2bb4a..65bcbe9 100644
--- a/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/AbstractPublisher.java
@@ -33,7 +33,7 @@
      * Adds a subscriber that listens for data produced by this publisher.
      *
      * @param subscriber a subscriber to receive data
-     * @throws IllegalArgumentException if an invalid subscriber was provided.
+     * @throws IllegalArgumentException if the subscriber is invalid.
      */
     public abstract void addDataSubscriber(DataSubscriber subscriber);
 
diff --git a/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
new file mode 100644
index 0000000..5fc1489
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/CarTelemetrydPublisher.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.publisher;
+
+import android.annotation.Nullable;
+import android.automotive.telemetry.internal.CarDataInternal;
+import android.automotive.telemetry.internal.ICarDataListener;
+import android.automotive.telemetry.internal.ICarTelemetryInternal;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.car.CarLog;
+import com.android.car.telemetry.TelemetryProto;
+import com.android.car.telemetry.databroker.DataSubscriber;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.utils.Slogf;
+
+import java.util.ArrayList;
+
+/**
+ * Publisher for cartelemtryd service (aka ICarTelemetry).
+ *
+ * <p>When a subscriber is added, the publisher binds to ICarTelemetryInternal and starts listening
+ * for incoming CarData. The matching CarData will be pushed to the subscriber. It unbinds itself
+ * from ICarTelemetryInternal if there are no subscribers.
+ *
+ * <p>See {@code packages/services/Car/cpp/telemetry/cartelemetryd} to learn more about the service.
+ */
+public class CarTelemetrydPublisher extends AbstractPublisher {
+    private static final boolean DEBUG = false;  // STOPSHIP if true
+    private static final String SERVICE_NAME = ICarTelemetryInternal.DESCRIPTOR + "/default";
+    private static final int BINDER_FLAGS = 0;
+
+    private final Object mLock = new Object();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private ICarTelemetryInternal mCarTelemetryInternal;
+
+    @GuardedBy("mLock")
+    private final ArrayList<DataSubscriber> mSubscribers = new ArrayList<>();
+
+    private final ICarDataListener mListener = new ICarDataListener.Stub() {
+        @Override
+        public void onCarDataReceived(CarDataInternal[] dataList) throws RemoteException {
+            if (DEBUG) {
+                Slog.d(CarLog.TAG_TELEMETRY,
+                        "Received " + dataList.length + " CarData from cartelemetryd");
+            }
+            onCarDataListReceived(dataList);
+        }
+    };
+
+    /** Called when binder for ICarTelemetry service is died. */
+    void onBinderDied() {
+        synchronized (mLock) {
+            if (mCarTelemetryInternal != null) {
+                mCarTelemetryInternal.asBinder().unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+            }
+            // TODO(b/193680465): try reconnecting again
+            mCarTelemetryInternal = null;
+        }
+    }
+
+    /**
+     * Returns true if connected, false if not connected.
+     *
+     * @throws IllegalStateException if it cannot connect to ICarTelemetryInternal service.
+     */
+    @GuardedBy("mLock")
+    private void connectToCarTelemetrydLocked() {
+        if (mCarTelemetryInternal != null) {
+            return;  // already connected
+        }
+        IBinder binder = ServiceManager.checkService(SERVICE_NAME);
+        if (binder == null) {
+            throw new IllegalStateException(
+                    "Failed to connect to ICarTelemetryInternal: service is not ready");
+        }
+        try {
+            binder.linkToDeath(this::onBinderDied, BINDER_FLAGS);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(
+                    "Failed to connect to ICarTelemetryInternal: linkToDeath failed", e);
+        }
+        mCarTelemetryInternal = ICarTelemetryInternal.Stub.asInterface(binder);
+        try {
+            mCarTelemetryInternal.setListener(mListener);
+        } catch (RemoteException e) {
+            binder.unlinkToDeath(this::onBinderDied, BINDER_FLAGS);
+            mCarTelemetryInternal = null;
+            throw new IllegalStateException(
+                    "Failed to connect to ICarTelemetryInternal: Cannot set CarData listener",
+                    e);
+        }
+    }
+
+    @VisibleForTesting
+    boolean isConnectedToCarTelemetryd() {
+        synchronized (mLock) {
+            return mCarTelemetryInternal != null;
+        }
+    }
+
+    @Override
+    public void addDataSubscriber(DataSubscriber subscriber) {
+        TelemetryProto.Publisher publisherParam = subscriber.getPublisherParam();
+        Preconditions.checkArgument(
+                publisherParam.getPublisherCase()
+                        == TelemetryProto.Publisher.PublisherCase.CARTELEMETRYD,
+                "Subscribers only with CarTelemetryd publisher are supported by this class.");
+        int carDataId = publisherParam.getCartelemetryd().getId();
+
+        synchronized (mLock) {
+            try {
+                connectToCarTelemetrydLocked();
+            } catch (IllegalStateException e) {
+                Slog.e(CarLog.TAG_TELEMETRY, "Failed to connect to ICarTelemetry", e);
+                // TODO(b/193680465): add retry reconnecting
+            }
+            mSubscribers.add(subscriber);
+        }
+
+        Slogf.d(CarLog.TAG_TELEMETRY, "Subscribing to CarDat.id=%d", carDataId);
+    }
+
+    @Override
+    public void removeDataSubscriber(DataSubscriber subscriber) {
+        // TODO(b/189142577): implement and disconnect from cartelemetryd if necessary
+    }
+
+    @Override
+    public void removeAllDataSubscribers() {
+        // TODO(b/189142577): implement and disconnect from cartelemetryd
+    }
+
+    @Override
+    public boolean hasDataSubscriber(DataSubscriber subscriber) {
+        synchronized (mLock) {
+            return mSubscribers.contains(subscriber);
+        }
+    }
+
+    /**
+     * Called when publisher receives new car data list. It's executed on a Binder thread.
+     */
+    private void onCarDataListReceived(CarDataInternal[] dataList) {
+        // TODO(b/189142577): implement
+    }
+}
diff --git a/service/src/com/android/car/user/AppLifecycleListener.java b/service/src/com/android/car/user/AppLifecycleListener.java
new file mode 100644
index 0000000..153ca85
--- /dev/null
+++ b/service/src/com/android/car/user/AppLifecycleListener.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+
+import com.android.car.CarLog;
+import com.android.internal.os.IResultReceiver;
+import com.android.server.utils.Slogf;
+
+import java.io.PrintWriter;
+
+/**
+ * Helper DTO to hold info about an app-based {@code UserLifecycleListener}
+ */
+final class AppLifecycleListener {
+
+    private static final String TAG = CarLog.tagFor(AppLifecycleListener.class);
+
+    private final DeathRecipient mDeathRecipient;
+
+    public final int uid;
+    public final String packageName;
+    public final IResultReceiver receiver;
+
+    AppLifecycleListener(int uid, String packageName, IResultReceiver receiver,
+            BinderDeathCallback binderDeathCallback) {
+        this.uid = uid;
+        this.packageName = packageName;
+        this.receiver = receiver;
+
+        mDeathRecipient = () -> binderDeathCallback.onBinderDeath(this);
+        Slogf.v(TAG, "linking death recipient %s", mDeathRecipient);
+        try {
+            receiver.asBinder().linkToDeath(mDeathRecipient, /* flags= */ 0);
+        } catch (RemoteException e) {
+            Slogf.wtf(TAG, "Cannot listen to death of %s", mDeathRecipient);
+        }
+    }
+
+    void onDestroy() {
+        Slogf.v(TAG, "onDestroy(): unlinking death recipient %s", mDeathRecipient);
+        receiver.asBinder().unlinkToDeath(mDeathRecipient, /* flags= */ 0);
+    }
+
+    void dump(PrintWriter writer) {
+        writer.printf("uid=%d, pkg=%s\n", uid, packageName);
+    }
+
+    String toShortString() {
+        return uid + "-" + packageName;
+    }
+
+    @Override
+    public String toString() {
+        return "AppLifecycleListener[uid=" + uid + ", pkg=" + packageName + "]";
+    }
+
+    interface BinderDeathCallback {
+        void onBinderDeath(AppLifecycleListener listener);
+    }
+}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 1fde509..00cb893 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -77,6 +77,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.Trace;
@@ -85,11 +86,11 @@
 import android.provider.Settings;
 import android.sysprop.CarProperties;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.TimingsTraceLog;
 import android.view.Display;
@@ -195,16 +196,19 @@
     private final Handler mHandler;
 
     /**
-     * List of listeners to be notified on new user activities events.
-     * This collection should be accessed and manipulated by mHandlerThread only.
+     * Internal listeners to be notified on new user activities events.
+     *
+     * <p>This collection should be accessed and manipulated by {@code mHandlerThread} only.
      */
     private final List<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
 
     /**
-     * List of lifecycle listeners by uid.
-     * This collection should be accessed and manipulated by mHandlerThread only.
+     * App listeners to be notified on new user activities events.
+     *
+     * <p>This collection should be accessed and manipulated by {@code mHandlerThread} only.
      */
-    private final SparseArray<IResultReceiver> mAppLifecycleListeners = new SparseArray<>();
+    private final ArrayMap<IBinder, AppLifecycleListener> mAppLifecycleListeners =
+            new ArrayMap<>();
 
     /**
      * User Id for the user switch in process, if any.
@@ -359,8 +363,7 @@
         checkHasDumpPermissionGranted("dump()");
 
         writer.println("*CarUserService*");
-        String indent = "  ";
-        handleDumpListeners(writer, indent);
+        handleDumpListeners(writer);
         writer.printf("User switch UI receiver %s\n", mUserSwitchUiReceiver);
         synchronized (mLockUser) {
             writer.println("User0Unlocked: " + mUser0Unlocked);
@@ -380,9 +383,10 @@
         List<UserInfo> allDrivers = getAllDrivers();
         int driversSize = allDrivers.size();
         writer.println("NumberOfDrivers: " + driversSize);
+        writer.increaseIndent();
         for (int i = 0; i < driversSize; i++) {
             int driverId = allDrivers.get(i).id;
-            writer.print(indent + "#" + i + ": id=" + driverId);
+            writer.printf("#%d: id=%d", i, driverId);
             List<UserInfo> passengers = getPassengers(driverId);
             int passengersSize = passengers.size();
             writer.print(" NumberPassengers: " + passengersSize);
@@ -398,38 +402,42 @@
             }
             writer.println();
         }
+        writer.decreaseIndent();
         writer.printf("EnablePassengerSupport: %s\n", mEnablePassengerSupport);
         writer.printf("User HAL timeout: %dms\n",  mHalTimeoutMs);
         writer.printf("Initial user: %s\n", mInitialUser);
 
         writer.println("Relevant overlayable properties");
         Resources res = mContext.getResources();
-        writer.printf("%sowner_name=%s\n", indent,
-                res.getString(com.android.internal.R.string.owner_name));
-        writer.printf("%sdefault_guest_name=%s\n", indent,
-                res.getString(R.string.default_guest_name));
+        writer.increaseIndent();
+        writer.printf("owner_name=%s\n", res.getString(com.android.internal.R.string.owner_name));
+        writer.printf("default_guest_name=%s\n", res.getString(R.string.default_guest_name));
+        writer.decreaseIndent();
         writer.printf("User switch in process=%d\n", mUserIdForUserSwitchInProcess);
         writer.printf("Request Id for the user switch in process=%d\n ",
                     mRequestIdForUserSwitchInProcess);
         writer.printf("System UI package name=%s\n", getSystemUiPackageName());
 
         writer.println("Relevant Global settings");
-        dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_USER_ID);
-        dumpGlobalProperty(writer, indent, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+        writer.increaseIndent();
+        dumpGlobalProperty(writer, CarSettings.Global.LAST_ACTIVE_USER_ID);
+        dumpGlobalProperty(writer, CarSettings.Global.LAST_ACTIVE_PERSISTENT_USER_ID);
+        writer.decreaseIndent();
 
         mInitialUserSetter.dump(writer);
     }
 
-    private void dumpGlobalProperty(PrintWriter writer, String indent, String property) {
+    private void dumpGlobalProperty(IndentingPrintWriter writer, String property) {
         String value = Settings.Global.getString(mContext.getContentResolver(), property);
-        writer.printf("%s%s=%s\n", indent, property, value);
+        writer.printf("%s=%s\n", property, value);
     }
 
-    private void handleDumpListeners(@NonNull PrintWriter writer, String indent) {
+    private void handleDumpListeners(IndentingPrintWriter writer) {
+        writer.increaseIndent();
         CountDownLatch latch = new CountDownLatch(1);
         mHandler.post(() -> {
             handleDumpServiceLifecycleListeners(writer);
-            handleDumpAppLifecycleListeners(writer, indent);
+            handleDumpAppLifecycleListeners(writer);
             latch.countDown();
         });
         int timeout = 5;
@@ -442,9 +450,10 @@
             Thread.currentThread().interrupt();
             writer.println("Interrupted waiting for handler thread to dump app and user listeners");
         }
+        writer.decreaseIndent();
     }
 
-    private void handleDumpServiceLifecycleListeners(@NonNull PrintWriter writer) {
+    private void handleDumpServiceLifecycleListeners(PrintWriter writer) {
         if (mUserLifecycleListeners.isEmpty()) {
             writer.println("No lifecycle listeners for internal services");
             return;
@@ -452,24 +461,24 @@
         int size = mUserLifecycleListeners.size();
         writer.printf("%d lifecycle listener%s for services\n", size, size == 1 ? "" : "s");
         String indent = "  ";
-        for (UserLifecycleListener listener : mUserLifecycleListeners) {
+        for (int i = 0; i < size; i++) {
+            UserLifecycleListener listener = mUserLifecycleListeners.get(i);
             writer.printf("%s%s\n", indent, FunctionalUtils.getLambdaName(listener));
         }
     }
 
-    private void handleDumpAppLifecycleListeners(@NonNull PrintWriter writer, String indent) {
+    private void handleDumpAppLifecycleListeners(IndentingPrintWriter writer) {
         int size = mAppLifecycleListeners.size();
         if (size == 0) {
             writer.println("No lifecycle listeners for apps");
             return;
         }
-        writer.printf("%d lifecycle listener%s for apps \n", size, size == 1 ? "" : "s");
+        writer.printf("%d lifecycle listener%s for apps\n", size, size == 1 ? "" : "s");
+        writer.increaseIndent();
         for (int i = 0; i < size; i++) {
-            int uid = mAppLifecycleListeners.keyAt(i);
-            IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
-            writer.printf("%suid: %d listener: %s\n", indent, uid,
-                    FunctionalUtils.getLambdaName(listener));
+            mAppLifecycleListeners.valueAt(i).dump(writer);
         }
+        writer.decreaseIndent();
     }
 
     /**
@@ -684,30 +693,45 @@
     }
 
     @Override
-    public void setLifecycleListenerForUid(IResultReceiver listener) {
+    public void setLifecycleListenerForApp(String packageName, IResultReceiver receiver) {
         int uid = Binder.getCallingUid();
-        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid);
-        checkInteractAcrossUsersPermission("setLifecycleListenerForUid" + uid);
+        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_SET_LIFECYCLE_LISTENER, uid, packageName);
+        checkInteractAcrossUsersPermission("setLifecycleListenerForApp-" + uid + "-" + packageName);
 
-        try {
-            listener.asBinder().linkToDeath(() -> onListenerDeath(uid), 0);
-        } catch (RemoteException e) {
-            Slog.wtf(TAG, "Cannot listen to death of " + uid);
-        }
-        mHandler.post(() -> mAppLifecycleListeners.append(uid, listener));
+        IBinder receiverBinder = receiver.asBinder();
+        AppLifecycleListener listener = new AppLifecycleListener(uid, packageName, receiver,
+                (l) -> onListenerDeath(l));
+        Slogf.d(TAG, "Adding %s (using binder %s)", listener, receiverBinder);
+        mHandler.post(() -> mAppLifecycleListeners.put(receiverBinder, listener));
     }
 
-    private void onListenerDeath(int uid) {
-        Slog.i(TAG, "Removing listeners for uid " + uid + " on binder death");
-        mHandler.post(() -> mAppLifecycleListeners.remove(uid));
+    private void onListenerDeath(AppLifecycleListener listener) {
+        Slogf.i(TAG, "Removing listener %s on binder death", listener);
+        mHandler.post(() -> mAppLifecycleListeners.remove(listener.receiver.asBinder()));
     }
 
     @Override
-    public void resetLifecycleListenerForUid() {
+    public void resetLifecycleListenerForApp(IResultReceiver receiver) {
         int uid = Binder.getCallingUid();
-        EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid);
-        checkInteractAcrossUsersPermission("resetLifecycleListenerForUid-" + uid);
-        mHandler.post(() -> mAppLifecycleListeners.remove(uid));
+        checkInteractAcrossUsersPermission("resetLifecycleListenerForApp-" + uid);
+        IBinder receiverBinder = receiver.asBinder();
+        mHandler.post(() -> {
+            AppLifecycleListener listener = mAppLifecycleListeners.get(receiverBinder);
+            if (listener == null) {
+                Slogf.e(TAG, "resetLifecycleListenerForApp(uid=%d): no listener for receiver", uid);
+                return;
+            }
+            if (listener.uid != uid) {
+                Slogf.e(TAG, "resetLifecycleListenerForApp(): uid mismatch (called by %d) for "
+                        + "listener %s", uid, listener);
+            }
+            EventLog.writeEvent(EventLogTags.CAR_USER_SVC_RESET_LIFECYCLE_LISTENER, uid,
+                    listener.packageName);
+            Slogf.d(TAG, "Removing %s (using binder %s)", listener, receiverBinder);
+            mAppLifecycleListeners.remove(receiverBinder);
+
+            listener.onDestroy();
+        });
     }
 
     /**
@@ -2102,23 +2126,17 @@
     private void handleNotifyAppUserLifecycleListeners(UserLifecycleEvent event) {
         int listenersSize = mAppLifecycleListeners.size();
         if (listenersSize == 0) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Slog.d(TAG, "No app listener to be notified of " + event);
-            }
+            Slogf.d(TAG, "No app listener to be notified of %s", event);
             return;
         }
         // Must use a different TimingsTraceLog because it's another thread
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Slog.d(TAG, "Notifying " + listenersSize + " app listeners of " + event);
-        }
+        Slogf.d(TAG, "Notifying %d app listeners of %s", listenersSize, event);
         int userId = event.getUserId();
         TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
         int eventType = event.getEventType();
         t.traceBegin("notify-app-listeners-user-" + userId + "-event-" + eventType);
         for (int i = 0; i < listenersSize; i++) {
-            int uid = mAppLifecycleListeners.keyAt(i);
-
-            IResultReceiver listener = mAppLifecycleListeners.valueAt(i);
+            AppLifecycleListener listener = mAppLifecycleListeners.valueAt(i);
             Bundle data = new Bundle();
             data.putInt(CarUserManager.BUNDLE_PARAM_ACTION, eventType);
 
@@ -2126,17 +2144,14 @@
             if (fromUserId != UserHandle.USER_NULL) {
                 data.putInt(CarUserManager.BUNDLE_PARAM_PREVIOUS_USER_ID, fromUserId);
             }
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Slog.d(TAG, "Notifying listener for uid " + uid);
-            }
+            Slogf.d(TAG, "Notifying listener %s", listener);
             EventLog.writeEvent(EventLogTags.CAR_USER_SVC_NOTIFY_APP_LIFECYCLE_LISTENER,
-                    uid, eventType, fromUserId, userId);
+                    listener.uid, listener.packageName, eventType, fromUserId, userId);
             try {
-                t.traceBegin("notify-app-listener-uid-" + uid);
-                listener.send(userId, data);
+                t.traceBegin("notify-app-listener-" + listener.toShortString());
+                listener.receiver.send(userId, data);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Error calling lifecycle listener", e);
+                Slogf.e(TAG, e, "Error calling lifecycle listener %s", listener);
             } finally {
                 t.traceEnd();
             }
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index fccaa8b..4bbb40a 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -326,6 +326,14 @@
         return mWatchdogPerfHandler.getResourceOveruseConfigurations(resourceOveruseFlag);
     }
 
+    /**
+     * Enables/disables the watchdog daemon client health check process.
+     */
+    public void controlProcessHealthCheck(boolean disable) {
+        ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
+        mWatchdogProcessHandler.controlProcessHealthCheck(disable);
+    }
+
     private void postRegisterToDaemonMessage() {
         CarServiceUtils.runOnMain(() -> {
             synchronized (mLock) {
diff --git a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
index cce3d15..c935f0a 100644
--- a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
@@ -240,6 +240,16 @@
         }
     }
 
+    /** Enables/disables the watchdog daemon client health check process. */
+    void controlProcessHealthCheck(boolean disable) {
+        try {
+            mCarWatchdogDaemonHelper.controlProcessHealthCheck(disable);
+        } catch (RemoteException e) {
+            Slogf.w(CarWatchdogService.TAG,
+                    "Cannot enable/disable the car watchdog daemon health check process: %s", e);
+        }
+    }
+
     private void onClientDeath(ICarWatchdogServiceCallback client, int timeout) {
         synchronized (mLock) {
             removeClientLocked(client.asBinder(), timeout);
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
index 4493806..f8d19d6 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeAdapter.java
@@ -66,25 +66,26 @@
         }
         if (mVolumeList[position] != null) {
             vh.id.setText(mVolumeList[position].id);
-            vh.maxVolume.setText(String.valueOf(mVolumeList[position].maxGain));
             vh.currentVolume.setText(String.valueOf(mVolumeList[position].currentGain));
             int color = mVolumeList[position].hasAudioFocus ? Color.GREEN : Color.GRAY;
             vh.requestButton.setBackgroundColor(color);
             if (position == 0) {
+                vh.maxVolume.setText("Max");
                 vh.upButton.setVisibility(View.INVISIBLE);
                 vh.downButton.setVisibility(View.INVISIBLE);
                 vh.requestButton.setVisibility(View.INVISIBLE);
                 vh.muteButton.setVisibility(View.INVISIBLE);
             } else {
+                vh.maxVolume.setText(String.valueOf(mVolumeList[position].maxGain));
                 vh.upButton.setVisibility(View.VISIBLE);
                 vh.downButton.setVisibility(View.VISIBLE);
                 vh.requestButton.setVisibility(View.VISIBLE);
                 vh.muteButton.setVisibility(mGroupMuteEnabled ? View.VISIBLE : View.INVISIBLE);
                 vh.upButton.setOnClickListener((view) -> {
-                    mFragment.adjustVolumeByOne(mVolumeList[position].groupId, true);
+                    mFragment.adjustVolumeUp(mVolumeList[position].groupId);
                 });
                 vh.downButton.setOnClickListener((view) -> {
-                    mFragment.adjustVolumeByOne(mVolumeList[position].groupId, false);
+                    mFragment.adjustVolumeDown(mVolumeList[position].groupId);
                 });
                 vh.muteButton.setChecked(mVolumeList[position].isMuted);
                 vh.muteButton.setOnClickListener((view) -> {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
index 7cbe344..2419511 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/CarAudioZoneVolumeFragment.java
@@ -19,9 +19,6 @@
 import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING;
 import static android.media.AudioManager.FLAG_PLAY_SOUND;
 
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
 import android.car.media.CarAudioManager;
 import android.media.AudioAttributes;
 import android.media.AudioAttributes.AttributeUsage;
@@ -55,7 +52,10 @@
     private static final int MSG_REQUEST_FOCUS = 1;
     private static final int MSG_FOCUS_CHANGED = 2;
     private static final int MSG_STOP_RINGTONE = 3;
+    private static final int MSG_ADJUST_VOLUME = 4;
     private static final long RINGTONE_STOP_TIME_MS = 3_000;
+    private static final int ADJUST_VOLUME_UP = 0;
+    private static final int ADJUST_VOLUME_DOWN = 1;
 
     private final int mZoneId;
     private final Object mLock = new Object();
@@ -71,10 +71,19 @@
     @GuardedBy("mLock")
     private Ringtone mRingtone;
 
-    public void sendVolumeChangedMessage(int groupId, int flags) {
+    void sendVolumeChangedMessage(int groupId, int flags) {
         mHandler.sendMessage(mHandler.obtainMessage(MSG_VOLUME_CHANGED, groupId, flags));
     }
 
+    void adjustVolumeUp(int groupId) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ADJUST_VOLUME, groupId, ADJUST_VOLUME_UP));
+    }
+
+    void adjustVolumeDown(int groupId) {
+        mHandler.sendMessage(mHandler
+                .obtainMessage(MSG_ADJUST_VOLUME, groupId, ADJUST_VOLUME_DOWN));
+    }
+
     private class VolumeHandler extends Handler {
         private AudioFocusListener mFocusListener;
 
@@ -108,10 +117,12 @@
                     mVolumeInfos[mGroupIdIndexMap.get(focusGroupId)].hasAudioFocus = true;
                     mCarAudioZoneVolumeAdapter.refreshVolumes(mVolumeInfos);
                     break;
-                default :
-                    Log.wtf(TAG,"VolumeHandler handleMessage called with unknown message"
+                case MSG_ADJUST_VOLUME:
+                    adjustVolumeByOne(msg.arg1, msg.arg2 == ADJUST_VOLUME_UP);
+                    break;
+                default:
+                    Log.wtf(TAG, "VolumeHandler handleMessage called with unknown message"
                             + msg.what);
-
             }
         }
     }
@@ -147,7 +158,6 @@
         CarAudioZoneVolumeInfo titlesInfo = new CarAudioZoneVolumeInfo();
         titlesInfo.id = "Group id";
         titlesInfo.currentGain = "Current";
-        titlesInfo.maxGain = "Max";
         mVolumeInfos[0] = titlesInfo;
 
         int i = 1;
@@ -158,13 +168,14 @@
             volumeInfo.id = String.valueOf(groupId);
             int current = mCarAudioManager.getGroupVolume(mZoneId, groupId);
             int max = mCarAudioManager.getGroupMaxVolume(mZoneId, groupId);
+            int min = mCarAudioManager.getGroupMinVolume(mZoneId, groupId);
             volumeInfo.currentGain = String.valueOf(current);
-            volumeInfo.maxGain = String.valueOf(max);
+            volumeInfo.maxGain = max;
+            volumeInfo.minGain = min;
             volumeInfo.isMuted = mCarAudioManager.isVolumeGroupMuted(mZoneId, groupId);
 
             mVolumeInfos[i] = volumeInfo;
-            if (DEBUG)
-            {
+            if (DEBUG) {
                 Log.d(TAG, groupId + " max: " + volumeInfo.maxGain + " current: "
                         + volumeInfo.currentGain + " is muted " + volumeInfo.isMuted);
             }
@@ -173,15 +184,29 @@
         mCarAudioZoneVolumeAdapter.refreshVolumes(mVolumeInfos);
     }
 
-    public void adjustVolumeByOne(int groupId, boolean up) {
+    private void adjustVolumeByOne(int groupId, boolean up) {
         if (mCarAudioManager == null) {
             Log.e(TAG, "CarAudioManager is null");
             return;
         }
         int current = mCarAudioManager.getGroupVolume(mZoneId, groupId);
-        int volume = (up ? min(mCarAudioManager.getGroupMaxVolume(mZoneId, groupId), current + 1)
-                : max(mCarAudioManager.getGroupMinVolume(mZoneId, groupId), current - 1));
-        mCarAudioManager.setGroupVolume(mZoneId, groupId, volume, AudioManager.FLAG_SHOW_UI);
+        CarAudioZoneVolumeInfo info = getVolumeInfo(groupId);
+        int volume = up ? current + 1 : current - 1;
+        if (volume > info.maxGain) {
+            if (DEBUG) {
+                Log.d(TAG, "Reached " + groupId + " max volume "
+                        + " limit " + volume);
+            }
+            return;
+        }
+        if (volume < info.minGain) {
+            if (DEBUG) {
+                Log.d(TAG, "Reached " + groupId + " min volume "
+                        + " limit " + volume);
+            }
+            return;
+        }
+        mCarAudioManager.setGroupVolume(mZoneId, groupId, volume, /* flags= */ 0);
         if (DEBUG) {
             Log.d(TAG, "Set group " + groupId + " volume "
                     + mCarAudioManager.getGroupVolume(mZoneId, groupId)
@@ -189,6 +214,10 @@
         }
     }
 
+    private CarAudioZoneVolumeInfo getVolumeInfo(int groupId) {
+        return mVolumeInfos[mGroupIdIndexMap.get(groupId)];
+    }
+
     public void toggleMute(int groupId) {
         if (mCarAudioManager == null) {
             Log.e(TAG, "CarAudioManager is null");
@@ -202,7 +231,7 @@
         }
     }
 
-    public void requestFocus(int groupId) {
+    void requestFocus(int groupId) {
         // Automatic volume change only works for primary audio zone.
         if (mZoneId == CarAudioManager.PRIMARY_AUDIO_ZONE) {
             mHandler.sendMessage(mHandler
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
index 2a2c38e..821d362 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/volume/VolumeTestFragment.java
@@ -62,7 +62,8 @@
     public static final class CarAudioZoneVolumeInfo {
         public int groupId;
         public String id;
-        public String maxGain;
+        public int maxGain;
+        public int minGain;
         public String currentGain;
         public boolean hasAudioFocus;
         public boolean isMuted;
diff --git a/tests/UserSwitchMonitorApp/Android.bp b/tests/UserSwitchMonitorApp/Android.bp
index 9aa39a9..b5f29eb 100644
--- a/tests/UserSwitchMonitorApp/Android.bp
+++ b/tests/UserSwitchMonitorApp/Android.bp
@@ -27,3 +27,18 @@
 
     sdk_version: "system_current",
 }
+
+// "Cloned" app used to make sure events are received by apps with shared uid
+android_app {
+    name: "UserSwitchMonitorApp2",
+
+    manifest: "AndroidManifest2.xml",
+
+    libs: [
+        "android.car-system-stubs",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "system_current",
+}
diff --git a/tests/UserSwitchMonitorApp/AndroidManifest.xml b/tests/UserSwitchMonitorApp/AndroidManifest.xml
index e78d690..fec167a 100644
--- a/tests/UserSwitchMonitorApp/AndroidManifest.xml
+++ b/tests/UserSwitchMonitorApp/AndroidManifest.xml
@@ -16,15 +16,17 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.google.android.car.userswitchmonitor">
+    package="com.google.android.car.userswitchmonitor"
+    android:sharedUserId="com.google.android.car.userswitchmonitor">
 
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
 
-    <application android:label="User Switch Monitor">
-        <service android:name=".UserSwitchMonitorService"/>
-        <receiver android:name=".BootCompletedReceiver" android:exported="true">
+    <application android:icon="@drawable/ic_launcher" android:label="User Switch Monitor">
+        <service android:name="com.google.android.car.userswitchmonitor.UserSwitchMonitorService"/>
+        <receiver android:name="com.google.android.car.userswitchmonitor.BootCompletedReceiver"
+                  android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
diff --git a/tests/UserSwitchMonitorApp/AndroidManifest2.xml b/tests/UserSwitchMonitorApp/AndroidManifest2.xml
new file mode 100644
index 0000000..bb38752
--- /dev/null
+++ b/tests/UserSwitchMonitorApp/AndroidManifest2.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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
+  -->
+
+<!-- "Cloned" app used to make sure events are received by apps with shared uid -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.car.userswitchmonitor2"
+    android:sharedUserId="com.google.android.car.userswitchmonitor">
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+
+    <application android:icon="@drawable/ic_launcher" android:label="User Switch Monitor">
+        <service android:name="com.google.android.car.userswitchmonitor.UserSwitchMonitorService"/>
+        <receiver android:name="com.google.android.car.userswitchmonitor.BootCompletedReceiver"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
index f76b0d6..73c5cc4 100644
--- a/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
+++ b/tests/UserSwitchMonitorApp/src/com/google/android/car/userswitchmonitor/UserSwitchMonitorService.java
@@ -41,6 +41,10 @@
 
     static final String TAG = "UserSwitchMonitor";
 
+    private static final String CMD_HELP = "help";
+    private static final String CMD_REGISTER = "register";
+    private static final String CMD_UNREGISTER = "unregister";
+
     private final Object mLock = new Object();
 
     private final int mUserId = android.os.Process.myUserHandle().getIdentifier();
@@ -64,11 +68,16 @@
         mContext = getApplicationContext();
         mCar = Car.createCar(mContext);
         mCarUserManager = (CarUserManager) mCar.getCarManager(Car.CAR_USER_SERVICE);
-        mCarUserManager.addListener((r)-> r.run(), mListener);
+        registerListener();
 
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
     }
 
+    private void registerListener() {
+        Log.d(TAG, "registerListener(): " + mListener);
+        mCarUserManager.addListener((r)-> r.run(), mListener);
+    }
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         Log.d(TAG, "onStartCommand(" + mUserId + "): " + intent);
@@ -79,11 +88,13 @@
                 NotificationManager.IMPORTANCE_MIN);
         mNotificationManager.createNotificationChannel(channel);
 
+        // Cannot use R.drawable because package name is different on app2
+        int iconResId = mContext.getApplicationInfo().icon;
         startForeground(startId,
                 new Notification.Builder(mContext, channelId)
                         .setContentText(name)
                         .setContentTitle(name)
-                        .setSmallIcon(R.drawable.ic_launcher)
+                        .setSmallIcon(iconResId)
                         .build());
 
         return super.onStartCommand(intent, flags, startId);
@@ -93,19 +104,29 @@
     public void onDestroy() {
         Log.d(TAG, "onDestroy(" + mUserId + ")");
 
-        if (mCarUserManager != null) {
-            mCarUserManager.removeListener(mListener);
-        } else {
-            Log.w(TAG, "Cannot remove listener because manager is null");
-        }
+        unregisterListener();
         if (mCar != null && mCar.isConnected()) {
             mCar.disconnect();
         }
         super.onDestroy();
     }
 
+    private void unregisterListener() {
+        Log.d(TAG, "unregisterListener(): " + mListener);
+        if (mCarUserManager != null) {
+            mCarUserManager.removeListener(mListener);
+        } else {
+            Log.w(TAG, "Cannot remove listener because manager is null");
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (args != null && args.length > 0) {
+            executeCommand(pw, args);
+            return;
+        }
+
         pw.printf("User id: %d\n", mUserId);
         synchronized (mLock) {
             if (mEvents.isEmpty()) {
@@ -127,4 +148,48 @@
         return null;
     }
 
+    private void executeCommand(PrintWriter pw, String[] args) {
+        String cmd = args[0];
+        switch (cmd) {
+            case CMD_HELP:
+                cmdHelp(pw);
+                break;
+            case CMD_REGISTER:
+                cmdRegister(pw);
+                break;
+            case CMD_UNREGISTER:
+                cmdUnregister(pw);
+                break;
+            default:
+                pw.printf("invalid command: %s\n\n",  cmd);
+                cmdHelp(pw);
+        }
+    }
+
+    private void cmdHelp(PrintWriter pw) {
+        pw.printf("Options:\n");
+        pw.printf("  help: show this help\n");
+        pw.printf("  register: register the service to receive events\n");
+        pw.printf("  unregister: unregister the service from receiving events\n");
+    }
+
+
+    private void cmdRegister(PrintWriter pw) {
+        pw.printf("registering listener %s\n", mListener);
+        runCmd(pw, () -> registerListener());
+    }
+
+    private void cmdUnregister(PrintWriter pw) {
+        pw.printf("unregistering listener %s\n", mListener);
+        runCmd(pw, () -> unregisterListener());
+    }
+
+    private void runCmd(PrintWriter pw, Runnable r) {
+        try {
+            r.run();
+        } catch (Exception e) {
+            Log.e(TAG, "error running command", e);
+            pw.printf("failed: %s\n", e);
+        }
+    }
 }
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
index 62f2b0a..2662eaf 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -18,15 +18,22 @@
 import static android.car.test.util.UserTestingHelper.clearUserLockCredentials;
 import static android.car.test.util.UserTestingHelper.setMaxSupportedUsers;
 import static android.car.test.util.UserTestingHelper.setUserLockCredentials;
+import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.car.Car;
 import android.car.testapi.BlockingUserLifecycleListener;
+import android.car.user.CarUserManager;
 import android.car.user.CarUserManager.UserLifecycleEvent;
 import android.content.pm.UserInfo;
+import android.os.Process;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
 
@@ -34,12 +41,15 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.util.List;
+
 public final class CarUserManagerTest extends CarMultiUserTestBase {
 
     private static final String TAG = CarUserManagerTest.class.getSimpleName();
 
     private static final int PIN = 2345;
 
+    private static final int START_TIMEOUT_MS = 20_000;
     private static final int SWITCH_TIMEOUT_MS = 70_000;
 
     private static final int sMaxNumberUsersBefore = UserManager.getMaxSupportedUsers();
@@ -92,6 +102,75 @@
         assertUserInfo(newGuest, loadedGuest);
     }
 
+    @Test
+    public void testLifecycleMultipleListeners() throws Exception {
+        int newUserId = createUser("Test").id;
+        Car car2 = Car.createCar(getContext().getApplicationContext());
+        CarUserManager mgr2 = (CarUserManager) car2.getCarManager(Car.CAR_USER_SERVICE);
+        CarUserManager mgr1 = mCarUserManager;
+        Log.d(TAG, "myUid=" + Process.myUid() + ",mgr1=" + mgr1 + ", mgr2=" + mgr2);
+        assertWithMessage("mgrs").that(mgr1).isNotSameInstanceAs(mgr2);
+
+        BlockingUserLifecycleListener listener1 = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(START_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .build();
+        BlockingUserLifecycleListener listener2 = BlockingUserLifecycleListener
+                .forSpecificEvents()
+                .forUser(newUserId)
+                .setTimeout(START_TIMEOUT_MS)
+                .addExpectedEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING)
+                .build();
+
+        Log.d(TAG, "registering listener1: " + listener1);
+        mgr1.addListener(Runnable::run, listener1);
+        Log.v(TAG, "ok");
+        try {
+            Log.d(TAG, "registering listener2: " + listener2);
+            mgr2.addListener(Runnable::run, listener2);
+            Log.v(TAG, "ok");
+            try {
+                IActivityManager am = ActivityManager.getService();
+                Log.d(TAG, "Starting user " + newUserId);
+                am.startUserInBackground(newUserId);
+                Log.v(TAG, "ok");
+
+                Log.d(TAG, "Waiting for events");
+                List<UserLifecycleEvent> events1 = listener1.waitForEvents();
+                Log.d(TAG, "events1: " + events1);
+                List<UserLifecycleEvent> events2 = listener2.waitForEvents();
+                Log.d(TAG, "events2: " + events2);
+                assertStartUserEvent(events1, newUserId);
+                assertStartUserEvent(events2, newUserId);
+            } finally {
+                Log.d(TAG, "unregistering listener2: " + listener2);
+                mgr2.removeListener(listener2);
+                Log.v(TAG, "ok");
+            }
+        } finally {
+            Log.d(TAG, "unregistering listener1: " + listener1);
+            mgr1.removeListener(listener1);
+            Log.v(TAG, "ok");
+        }
+    }
+
+    private void assertStartUserEvent(List<UserLifecycleEvent> events, @UserIdInt int userId) {
+        assertWithMessage("events").that(events).hasSize(1);
+
+        UserLifecycleEvent event = events.get(0);
+        assertWithMessage("type").that(event.getEventType())
+                .isEqualTo(USER_LIFECYCLE_EVENT_TYPE_STARTING);
+        assertWithMessage("user id on %s", event).that(event.getUserId()).isEqualTo(userId);
+        assertWithMessage("user handle on %s", event).that(event.getUserHandle().getIdentifier())
+                .isEqualTo(userId);
+        assertWithMessage("previous user id on %s", event).that(event.getPreviousUserId())
+                .isEqualTo(UserHandle.USER_NULL);
+        assertWithMessage("previous user handle on %s", event).that(event.getPreviousUserHandle())
+                .isNull();
+    }
+
     /**
      * Tests resume behavior when current user is ephemeral guest, a new guest user should be
      * created and switched to.
diff --git a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
index 36e4361..64c68fc 100644
--- a/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
+++ b/tests/carservice_test/src/com/android/car/garagemode/ControllerTest.java
@@ -81,8 +81,10 @@
     @Mock private CarPowerManager mCarPowerManagerMock;
     @Mock private CarUserService mCarUserServiceMock;
     @Mock private SystemInterface mSystemInterfaceMock;
+    @Mock private CarPowerManagementService mCarPowerManagementServiceMock;
     private CarUserService mCarUserServiceOriginal;
     private SystemInterface mSystemInterfaceOriginal;
+    private CarPowerManagementService mCarPowerManagementServiceOriginal;
     @Captor private ArgumentCaptor<Intent> mIntentCaptor;
     @Captor private ArgumentCaptor<Integer> mIntegerCaptor;
 
@@ -113,10 +115,15 @@
         mController.setCarPowerManager(mCarPowerManagerMock);
         mFuture = new CompletableFuture<>();
         mCarUserServiceOriginal = CarLocalServices.getService(CarUserService.class);
+        mCarPowerManagementServiceOriginal = CarLocalServices.getService(
+                CarPowerManagementService.class);
         CarLocalServices.removeServiceForTest(CarUserService.class);
         CarLocalServices.addService(CarUserService.class, mCarUserServiceMock);
         CarLocalServices.removeServiceForTest(SystemInterface.class);
         CarLocalServices.addService(SystemInterface.class, mSystemInterfaceMock);
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+        CarLocalServices.addService(CarPowerManagementService.class,
+                mCarPowerManagementServiceMock);
         doReturn(new ArrayList<Integer>()).when(mCarUserServiceMock)
                 .startAllBackgroundUsersInGarageMode();
         doNothing().when(mSystemInterfaceMock)
@@ -129,6 +136,9 @@
         CarLocalServices.addService(CarUserService.class, mCarUserServiceOriginal);
         CarLocalServices.removeServiceForTest(SystemInterface.class);
         CarLocalServices.addService(SystemInterface.class, mSystemInterfaceOriginal);
+        CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
+        CarLocalServices.addService(CarPowerManagementService.class,
+                mCarPowerManagementServiceOriginal);
     }
 
     @Test
@@ -229,13 +239,10 @@
 
     @Test
     public void testInitAndRelease() {
-        CarPowerManagementService mockCarPowerManagementService =
-                mock(CarPowerManagementService.class);
 
         GarageMode garageMode = mock(GarageMode.class);
         Controller controller = new Controller(mContextMock, mLooperMock, mWakeupPolicy,
                 mHandlerMock, garageMode);
-        CarLocalServices.addService(CarPowerManagementService.class, mockCarPowerManagementService);
 
         controller.init();
         controller.release();
@@ -308,5 +315,4 @@
         controller.onStateChanged(CarPowerStateListener.INVALID , null);
         verify(controller, never()).resetGarageMode();
     }
-
 }
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
index c67d3d8..99bbc4c 100644
--- a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -193,6 +193,13 @@
         verify(mFakeCarWatchdog).actionTakenOnResourceOveruse(eq(actions));
     }
 
+    @Test
+    public void testIndirectCall_controlProcessHealthCheck() throws Exception {
+        mCarWatchdogDaemonHelper.controlProcessHealthCheck(true);
+
+        verify(mFakeCarWatchdog).controlProcessHealthCheck(eq(true));
+    }
+
     /*
      * Test that the {@link CarWatchdogDaemonHelper} throws {@code IllegalArgumentException} when
      * trying to register already-registered service again.
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java b/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
index ff50677..2ab14dc 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/MockedPowerHalService.java
@@ -20,6 +20,8 @@
 import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateReq;
 import android.util.Log;
 
+import com.android.car.CarServiceUtils;
+
 import java.util.LinkedList;
 
 public class MockedPowerHalService extends PowerHalService {
@@ -47,7 +49,8 @@
                 mock(UserHalService.class),
                 mock(DiagnosticHalService.class),
                 mock(ClusterHalService.class),
-                mock(HalClient.class));
+                mock(HalClient.class),
+                CarServiceUtils.getHandlerThread(VehicleHal.class.getSimpleName()));
         return mockedVehicleHal;
     }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
index 763b680..4aa9a81 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/VehicleHalTest.java
@@ -35,6 +35,10 @@
 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.car.CarServiceUtils;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,6 +73,10 @@
     @Mock private ClusterHalService mClusterHalService;
     @Mock private HalClient mHalClient;
 
+    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
+            VehicleHal.class.getSimpleName());
+    private final Handler mHandler = new Handler(mHandlerThread.getLooper());
+
     private VehicleHal mVehicleHal;
 
     /** Hal services configurations */
@@ -78,7 +86,7 @@
     public void setUp() throws Exception {
         mVehicleHal = new VehicleHal(mPowerHalService,
                 mPropertyHalService, mInputHalService, mVmsHalService, mUserHalService,
-                mDiagnosticHalService, mClusterHalService, mHalClient);
+                mDiagnosticHalService, mClusterHalService, mHalClient, mHandlerThread);
 
         mConfigs.clear();
 
@@ -185,7 +193,8 @@
         propValues.add(propValue);
 
         // Act
-        mVehicleHal.onPropertyEvent(propValues);
+        mHandler.post(() -> mVehicleHal.onPropertyEvent(propValues));
+        CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
         verify(dispatchList).add(propValue);
@@ -201,7 +210,8 @@
         int areaId = VehicleHal.NO_AREA;
 
         // Act
-        mVehicleHal.onPropertySetError(errorCode, propId, areaId);
+        mHandler.post(() -> mVehicleHal.onPropertySetError(errorCode, propId, areaId));
+        CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
         verify(mPowerHalService).onPropertySetError(propId, areaId, errorCode);
@@ -215,7 +225,8 @@
         int areaId = VehicleHal.NO_AREA;
 
         // Act
-        mVehicleHal.onPropertySetError(errorCode, propId, areaId);
+        mHandler.post(() -> mVehicleHal.onPropertySetError(errorCode, propId, areaId));
+        CarServiceUtils.runOnLooperSync(mHandlerThread.getLooper(), () -> {});
 
         // Assert
         verify(mPowerHalService).onPropertySetError(propId, areaId, errorCode);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java
index 774da25..344fb04 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/ScriptExecutorTest.java
@@ -16,6 +16,8 @@
 
 package com.android.car.telemetry;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.fail;
 
 import android.car.telemetry.IScriptExecutor;
@@ -47,12 +49,17 @@
 
 
     private static final class ScriptExecutorListener extends IScriptExecutorListener.Stub {
+        public Bundle mSavedBundle;
+        public final CountDownLatch mSuccessLatch = new CountDownLatch(1);
+
         @Override
         public void onScriptFinished(byte[] result) {
         }
 
         @Override
         public void onSuccess(Bundle stateToPersist) {
+            mSavedBundle = stateToPersist;
+            mSuccessLatch.countDown();
         }
 
         @Override
@@ -60,7 +67,7 @@
         }
     }
 
-    private final IScriptExecutorListener mFakeScriptExecutorListener =
+    private final ScriptExecutorListener mFakeScriptExecutorListener =
             new ScriptExecutorListener();
 
     // TODO(b/189241508). Parsing of publishedData is not implemented yet.
@@ -69,15 +76,16 @@
     private final Bundle mSavedState = new Bundle();
 
     private static final String LUA_SCRIPT =
-            "function hello(data, state)\n"
-            + "    print(\"Hello World\")\n"
-            + "end\n";
+            "function hello(state)\n"
+                    + "    print(\"Hello World\")\n"
+                    + "end\n";
 
     private static final String LUA_METHOD = "hello";
 
     private final CountDownLatch mBindLatch = new CountDownLatch(1);
 
     private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
+    private static final int SCRIPT_SUCCESS_TIMEOUT_SEC = 10;
 
     private final ServiceConnection mScriptExecutorConnection =
             new ServiceConnection() {
@@ -93,6 +101,22 @@
                 }
             };
 
+    // Helper method to invoke the script and wait for it to complete and return the result.
+    public void runScriptAndWaitForResult(String script, String function, Bundle previousState)
+            throws RemoteException {
+        mScriptExecutor.invokeScript(script, function, mPublishedData, previousState,
+                mFakeScriptExecutorListener);
+        try {
+            if (!mFakeScriptExecutorListener.mSuccessLatch.await(SCRIPT_SUCCESS_TIMEOUT_SEC,
+                    TimeUnit.SECONDS)) {
+                fail("Failed to get on_success called by the script on time");
+            }
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+    }
+
     @Before
     public void setUp() throws InterruptedException {
         mContext.bindIsolatedService(new Intent(mContext, ScriptExecutor.class),
@@ -119,5 +143,129 @@
             fail(e.getMessage());
         }
     }
+
+    @Test
+    public void invokeScript_returnsResult() throws RemoteException {
+        String returnResultScript =
+                "function hello(state)\n"
+                        + "    result = {hello=\"world\"}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(returnResultScript, "hello", mSavedState);
+
+        // Expect to get back a bundle with a single string key: string value pair:
+        // {"hello": "world"}
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(1);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("hello")).isEqualTo("world");
+    }
+
+    @Test
+    public void invokeScript_allSupportedTypes() throws RemoteException {
+        String script =
+                "function knows(state)\n"
+                        + "    result = {string=\"hello\", boolean=true, integer=1, number=1.1}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(script, "knows", mSavedState);
+
+        // Expect to get back a bundle with 4 keys, each corresponding to a distinct supported type.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(4);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("string")).isEqualTo("hello");
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getBoolean("boolean")).isEqualTo(true);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getInt("integer")).isEqualTo(1);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getDouble("number")).isEqualTo(1.1);
+    }
+
+    @Test
+    public void invokeScript_skipsUnsupportedTypes() throws RemoteException {
+        String script =
+                "function nested(state)\n"
+                        + "    result = {string=\"hello\", boolean=true, integer=1, number=1.1}\n"
+                        + "    result.nested_table = {x=0, y=0}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(script, "nested", mSavedState);
+
+        // Bundle does not contain any value under "nested_table" key, because nested tables are
+        // not supported yet.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(4);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("nested_table")).isNull();
+    }
+
+    @Test
+    public void invokeScript_emptyBundle() throws RemoteException {
+        String script =
+                "function empty(state)\n"
+                        + "    result = {}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+
+
+        runScriptAndWaitForResult(script, "empty", mSavedState);
+
+        // If a script returns empty table as the result, we get an empty bundle.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle).isNotNull();
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void invokeScript_processPreviousStateAndReturnResult() throws RemoteException {
+        // Here we verify that the script actually processes provided state from a previous run
+        // and makes calculation based on that and returns the result.
+        // TODO(b/189241508): update function signatures.
+        String script =
+                "function update(state)\n"
+                        + "    result = {y = state.x+1}\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+        Bundle previousState = new Bundle();
+        previousState.putInt("x", 1);
+
+
+        runScriptAndWaitForResult(script, "update", previousState);
+
+        // Verify that y = 2, because y = x + 1 and x = 1.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(1);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getInt("y")).isEqualTo(2);
+    }
+
+    @Test
+    public void invokeScript_allSupportedTypesWorkRoundTripWithKeyNamesPreserved()
+            throws RemoteException {
+        // Here we verify that all supported types in supplied previous state Bundle are interpreted
+        // by the script as expected.
+        // TODO(b/189241508): update function signatures.
+        String script =
+                "function update_all(state)\n"
+                        + "    result = {}\n"
+                        + "    result.integer = state.integer + 1\n"
+                        + "    result.number = state.number + 0.1\n"
+                        + "    result.boolean = not state.boolean\n"
+                        + "    result.string = state.string .. \"CADABRA\"\n"
+                        + "    on_success(result)\n"
+                        + "end\n";
+        Bundle previousState = new Bundle();
+        previousState.putInt("integer", 1);
+        previousState.putDouble("number", 0.1);
+        previousState.putBoolean("boolean", false);
+        previousState.putString("string", "ABRA");
+
+
+        runScriptAndWaitForResult(script, "update_all", previousState);
+
+        // Verify that keys are preserved but the values are modified as expected.
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.size()).isEqualTo(4);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getInt("integer")).isEqualTo(2);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getDouble("number")).isEqualTo(0.2);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getBoolean("boolean")).isEqualTo(true);
+        assertThat(mFakeScriptExecutorListener.mSavedBundle.getString("string")).isEqualTo(
+                "ABRACADABRA");
+    }
 }
 
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
index 931a557..89db3f6 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
@@ -81,7 +81,7 @@
         // Checks that mMockDataBroker's setOnScriptFinishedCallback is called after it's injected
         // into controller's constructor with @InjectMocks
         verify(mMockDataBroker).setOnScriptFinishedCallback(
-                any(DataBrokerController.ScriptFinishedCallback.class));
+                any(DataBroker.ScriptFinishedCallback.class));
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java
index 71dace2..f4cde37 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerUnitTest.java
@@ -158,22 +158,54 @@
 
     @Test
     public void testAddMetricsConfiguration_newMetricsConfig() {
+        mDataBroker.addMetricsConfiguration(METRICS_CONFIG_BAR);
+
+        waitForHandlerThreadToFinish();
+        assertThat(mDataBroker.getSubscriptionMap()).hasSize(1);
+        assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_BAR.getName());
+        // there should be one data subscriber in the subscription list of METRICS_CONFIG_BAR
+        assertThat(mDataBroker.getSubscriptionMap().get(METRICS_CONFIG_BAR.getName())).hasSize(1);
+    }
+
+
+    @Test
+    public void testAddMetricsConfiguration_duplicateMetricsConfig_shouldDoNothing() {
+        // this metrics config has already been added in setUp()
         mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
 
         waitForHandlerThreadToFinish();
+        assertThat(mDataBroker.getSubscriptionMap()).hasSize(1);
         assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_FOO.getName());
-        // there should be one data subscriber in the subscription list of METRICS_CONFIG_FOO
         assertThat(mDataBroker.getSubscriptionMap().get(METRICS_CONFIG_FOO.getName())).hasSize(1);
     }
 
     @Test
-    public void testAddMetricsConfiguration_multipleMetricsConfigsSamePublisher() {
+    public void testRemoveMetricsConfiguration_shouldRemoveAllAssociatedTasks() {
         mDataBroker.addMetricsConfiguration(METRICS_CONFIG_FOO);
         mDataBroker.addMetricsConfiguration(METRICS_CONFIG_BAR);
+        ScriptExecutionTask taskWithMetricsConfigBar = new ScriptExecutionTask(
+                new DataSubscriber(mDataBroker, METRICS_CONFIG_BAR, SUBSCRIBER_BAR, PRIORITY_HIGH),
+                new Bundle(),
+                SystemClock.elapsedRealtime());
+        PriorityBlockingQueue<ScriptExecutionTask> taskQueue = mDataBroker.getTaskQueue();
+        taskQueue.add(mHighPriorityTask); // associated with METRICS_CONFIG_FOO
+        taskQueue.add(mLowPriorityTask); // associated with METRICS_CONFIG_FOO
+        taskQueue.add(taskWithMetricsConfigBar); // associated with METRICS_CONFIG_BAR
+        assertThat(taskQueue).hasSize(3);
+
+        mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_FOO);
 
         waitForHandlerThreadToFinish();
-        assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_FOO.getName());
-        assertThat(mDataBroker.getSubscriptionMap()).containsKey(METRICS_CONFIG_BAR.getName());
+        assertThat(taskQueue).hasSize(1);
+        assertThat(taskQueue.poll()).isEqualTo(taskWithMetricsConfigBar);
+    }
+
+    @Test
+    public void testRemoveMetricsConfiguration_whenMetricsConfigNonExistent_shouldDoNothing() {
+        mDataBroker.removeMetricsConfiguration(METRICS_CONFIG_BAR);
+
+        waitForHandlerThreadToFinish();
+        assertThat(mDataBroker.getSubscriptionMap()).hasSize(0);
     }
 
     private void waitForHandlerThreadToFinish() {
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
new file mode 100644
index 0000000..6e04768
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.publisher;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.automotive.telemetry.internal.ICarDataListener;
+import android.automotive.telemetry.internal.ICarTelemetryInternal;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+import com.android.car.telemetry.TelemetryProto;
+import com.android.car.telemetry.databroker.DataSubscriber;
+
+import org.junit.Before;
+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;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CarTelemetrydPublisherTest extends AbstractExtendedMockitoTestCase {
+    private static final String SERVICE_NAME = ICarTelemetryInternal.DESCRIPTOR + "/default";
+    private static final int CAR_DATA_ID_1 = 100;
+    private static final TelemetryProto.Publisher PUBLISHER_PARAMS_1 =
+            TelemetryProto.Publisher.newBuilder()
+                    .setCartelemetryd(TelemetryProto.CarTelemetrydPublisher.newBuilder()
+                            .setId(CAR_DATA_ID_1))
+                    .build();
+
+    @Mock private IBinder mMockBinder;
+    @Mock private ICarTelemetryInternal mMockCarTelemetryInternal;
+    @Mock private DataSubscriber mMockDataSubscriber;
+
+    private final CarTelemetrydPublisher mPublisher = new CarTelemetrydPublisher();
+
+    // ICarTelemetryInternal side of the listener.
+    @Captor private ArgumentCaptor<ICarDataListener> mCarDataListenerCaptor;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mMockDataSubscriber.getPublisherParam()).thenReturn(PUBLISHER_PARAMS_1);
+        doNothing().when(mMockCarTelemetryInternal).setListener(mCarDataListenerCaptor.capture());
+    }
+
+    private void mockICarTelemetryInternalBinder() {
+        when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockCarTelemetryInternal);
+        when(mMockCarTelemetryInternal.asBinder()).thenReturn(mMockBinder);
+        doReturn(mMockBinder).when(() -> ServiceManager.checkService(SERVICE_NAME));
+    }
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder.spyStatic(ServiceManager.class);
+    }
+
+    @Test
+    public void testAddDataSubscriber_registersNewListener() throws Exception {
+        mockICarTelemetryInternalBinder();
+
+        mPublisher.addDataSubscriber(mMockDataSubscriber);
+
+        assertThat(mCarDataListenerCaptor.getAllValues()).hasSize(1);
+        assertThat(mPublisher.isConnectedToCarTelemetryd()).isTrue();
+        assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
+    }
+
+    // TODO(b/189142577): add test cases when connecting to cartelemetryd fails
+
+
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
index dad880c..8410d02 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
@@ -75,7 +75,7 @@
                             .setVehiclePropertyId(-200))
                     .build();
 
-    // mMockCarPropertyService supported car property list.
+    // CarPropertyConfigs for mMockCarPropertyService.
     private static final CarPropertyConfig<Integer> PROP_CONFIG_1 =
             CarPropertyConfig.newBuilder(Integer.class, PROP_ID_1, AREA_ID).setAccess(
                     CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ).build();
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index b12aa27..8140e79 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -31,6 +31,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyList;
@@ -1245,6 +1246,23 @@
         assertPackageInfoEquals(actualPackageInfos, expectedPackageInfos);
     }
 
+    @Test
+    public void testSetProcessHealthCheckEnabled() throws Exception {
+        mCarWatchdogService.controlProcessHealthCheck(true);
+
+        verify(mMockCarWatchdogDaemon).controlProcessHealthCheck(eq(true));
+    }
+
+    @Test
+    public void testSetProcessHealthCheckEnabledWithDisconnectedDaemon() throws Exception {
+        crashWatchdogDaemon();
+
+        assertThrows(IllegalStateException.class,
+                () -> mCarWatchdogService.controlProcessHealthCheck(false));
+
+        verify(mMockCarWatchdogDaemon, never()).controlProcessHealthCheck(anyBoolean());
+    }
+
     private void mockWatchdogDaemon() {
         when(mMockBinder.queryLocalInterface(anyString())).thenReturn(mMockCarWatchdogDaemon);
         when(mMockCarWatchdogDaemon.asBinder()).thenReturn(mMockBinder);