Merge "Default Bluetooth profiles for Automotive" into rvc-dev
diff --git a/car-lib/src/android/car/navigation/navigation_state.proto b/car-lib/src/android/car/navigation/navigation_state.proto
index f6161e0..6c4f2bd 100644
--- a/car-lib/src/android/car/navigation/navigation_state.proto
+++ b/car-lib/src/android/car/navigation/navigation_state.proto
@@ -32,7 +32,8 @@
 // Margins: The referenced image does not have internal margins.
 // Format: Content URI must reference a file with MIME type
 //         'image/png', 'image/jpeg' or 'image/bmp'.
-// Color: Images can be either "tintable" or not. A "tintable" image is such that
+// Color: Images can be either "tintable" or not. A "tintable" image is such
+// that
 //        all its content is defined in its alpha channel, while its color
 //        (all other channels) can be altered without losing information
 //        (e.g. icons). A non "tintable" images contains information in all its
@@ -40,8 +41,8 @@
 // Caching: Given the same image reference and the same requested size,
 //          it is assumed that the exact same image will always be returned.
 //          This means that it should be safe to cache an image once requested
-//          the first time, using this image reference plus requested size as key,
-//          for as long as needed.
+//          the first time, using this image reference plus requested size as
+//          key, for as long as needed.
 message ImageReference {
   // A URI defining the location that the image can be retrieved from.
   //
@@ -95,7 +96,8 @@
   // in the vehicle.
   //
   // For example, a distance of 1200 meters in ES_es locale could be
-  // represented with `display_value` of "1,2" and `display_units` of KILOMETERS.
+  // represented with `display_value` of "1,2" and `display_units` of
+  // KILOMETERS.
   string display_value = 2;
 
   // The distance unit that should be used to display the distance value
@@ -106,7 +108,6 @@
 
 // Information about a maneuver that the driver will be required to perform.
 message Maneuver {
-
   // Next ID: 57
   enum Type {
     // Maneuver type is unknown, no maneuver information should be displayed.
@@ -119,57 +120,92 @@
     NAME_CHANGE = 2;
 
     // No turn, from 0 (included) to 10 (excluded) degrees. Used when we just
-    // wish to say "Keep left" or "Keep right". Note that this is used in
-    // contrast to STRAIGHT for disambiguating cases where there is more than
-    // one option to go into the same general direction.
+    // wish to say "Keep left". Note that this is used in contrast to STRAIGHT
+    // for disambiguating cases where there is more than one option to go into
+    // the same general direction.
     KEEP_LEFT = 3;
+    // No turn, from 0 (included) to 10 (excluded) degrees. Used when we just
+    // wish to say "Keep right". Note that this is used in contrast to STRAIGHT
+    // for disambiguating cases where there is more than one option to go into
+    // the same general direction.
     KEEP_RIGHT = 4;
 
-    // Slight turn at an intersection, from 10 (included) to 45 (excluded)
+    // Slight left turn at an intersection, from 10 (included) to 45 (excluded)
     // degrees.
     TURN_SLIGHT_LEFT = 5;
+    // Slight right turn at an intersection, from 10 (included) to 45 (excluded)
+    // degrees.
     TURN_SLIGHT_RIGHT = 6;
 
-    // Regular turn at an intersection, from 45 (included) to 135 (excluded)
-    // degrees.
+    // Regular left turn at an intersection, from 45 (included) to 135
+    // (excluded) degrees.
     TURN_NORMAL_LEFT = 7;
+    // Regular right turn at an intersection, from 45 (included) to 135
+    // (excluded) degrees.
     TURN_NORMAL_RIGHT = 8;
 
-    // Sharp turn at an intersection, from 135 (included) to 175 (excluded)
-    // degrees
+    // Sharp left turn at an intersection, from 135 (included) to 175 (excluded)
+    // degrees.
     TURN_SHARP_LEFT = 9;
+    // Sharp right turn at an intersection, from 135 (included) to 175
+    // (excluded) degrees.
     TURN_SHARP_RIGHT = 10;
 
-    // A turn onto the opposite side of the same street, from 175 (included) to
-    // 180 (included) degrees.
+    // A left turn onto the opposite side of the same street, from 175
+    // (included) to 180 (included) degrees.
     U_TURN_LEFT = 11;
+    // A right turn onto the opposite side of the same street, from 175
+    // (included) to 180 (included) degrees.
     U_TURN_RIGHT = 12;
 
-    // A turn to enter a turnpike or freeway. See TURN_NORMAL_LEFT,
-    // TURN_SLIGHT_RIGHT, etc., for the difference between slight, sharp, etc.
+    // A slight left turn to enter a turnpike or freeway. See TURN_SLIGHT_LEFT
+    // for the definition of slight.
     ON_RAMP_SLIGHT_LEFT = 13;
+    // A slight right turn to enter a turnpike or freeway. See TURN_SLIGHT_RIGHT
+    // for the definition of slight.
     ON_RAMP_SLIGHT_RIGHT = 14;
+    // A normal left turn to enter a turnpike or freeway. See TURN_NORMAL_LEFT
+    // for the definition of normal.
     ON_RAMP_NORMAL_LEFT = 15;
+    // A normal right turn to enter a turnpike or freeway. See TURN_NORMAL_RIGHT
+    // for the definition of normal.
     ON_RAMP_NORMAL_RIGHT = 16;
+    // A sharp left turn to enter a turnpike or freeway. See TURN_SHARP_LEFT
+    // for the definition of sharp.
     ON_RAMP_SHARP_LEFT = 17;
+    // A sharp right turn to enter a turnpike or freeway. See TURN_SHARP_RIGHT
+    // for the definition of sharp.
     ON_RAMP_SHARP_RIGHT = 18;
+    // A left u-turn to enter a turnpike or freeway. See U_TURN_LEFT for the
+    // definition of u-turn.
     ON_RAMP_U_TURN_LEFT = 19;
+    // A right u-turn to enter a turnpike or freeway. See U_TURN_RIGHT for the
+    // definition of u-turn.
     ON_RAMP_U_TURN_RIGHT = 20;
 
-    // A turn to exit a turnpike or freeway. See TURN_NORMAL_LEFT,
-    // TURN_SLIGHT_RIGHT, etc., for the difference between slight, sharp, etc.
+    // A slight left turn to exit a turnpike or freeway. See TURN_SLIGHT_LEFT
+    // for the definition of slight.
     OFF_RAMP_SLIGHT_LEFT = 21;
+    // A slight right turn to exit a turnpike or freeway. See TURN_SLIGHT_RIGHT
+    // for the definition of slight.
     OFF_RAMP_SLIGHT_RIGHT = 22;
+    // A left turn to exit a turnpike or freeway. See TURN_NORMAL_LEFT
+    // for the definition of normal.
     OFF_RAMP_NORMAL_LEFT = 23;
+    // A right turn to exit a turnpike or freeway. See TURN_NORMAL_RIGHT
+    // for the definition of normal.
     OFF_RAMP_NORMAL_RIGHT = 24;
 
-    // Road diverges (e.g. "Keep left/right at the fork").
+    // Road diverges (e.g. "Keep left at the fork").
     FORK_LEFT = 25;
+    // Road diverges (e.g. "Keep right at the fork").
     FORK_RIGHT = 26;
 
-    // Current road joins another (e.g. "Merge left/right onto Main St.").
+    // Current road joins another (e.g. "Merge right onto Main St.").
     MERGE_LEFT = 27;
+    // Current road joins another (e.g. "Merge left onto Main St.").
     MERGE_RIGHT = 28;
+    // Current road joins another (e.g. "Merge onto Main St.").
     MERGE_SIDE_UNSPECIFIED = 54;
 
     // Roundabout entrance on which the current road ends (e.g. "Enter the
@@ -180,36 +216,90 @@
     // the roundabout").
     ROUNDABOUT_EXIT = 30;
 
-    // The following are entrance and exit (e.g. "At the roundabout, take Nth
-    // exit") on a clockwise roundabout (as seen from above, typical for
-    // left-hand drive countries) where the exit is a particular turn amount
-    // (sharp right, vs. normal left, etc. - see the definitions for
-    // TURN_SHARP_LEFT, TURN_SLIGHT_RIGHT, etc., for a definition of what "sharp"
-    // vs. "normal" vs. "slight" is.
+    // Entrance and exit (e.g. "At the roundabout, take Nth exit") on a
+    // clockwise roundabout (as seen from above, typical for left-hand drive
+    // countries).
     ROUNDABOUT_ENTER_AND_EXIT_CW = 55;
+    // Entrance and sharp right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SHARP_RIGHT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SHARP_RIGHT = 31;
+    // Entrance and regular right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_NORMAL_RIGHT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CW_NORMAL_RIGHT = 32;
+    // Entrance and slight right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SLIGHT_RIGHT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SLIGHT_RIGHT = 33;
+    // Entrance and straight exit (e.g. "At the roundabout, take Nth exit") on a
+    // clockwise roundabout (as seen from above, typical for left-hand drive
+    // countries).
     ROUNDABOUT_ENTER_AND_EXIT_CW_STRAIGHT = 34;
+    // Entrance and sharp left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SHARP_LEFT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SHARP_LEFT = 35;
+    // Entrance and regular left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_NORMAL_LEFT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CW_NORMAL_LEFT = 36;
+    // Entrance and slight left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a clockwise roundabout (as seen from above, typical for
+    // left-hand drive countries). See TURN_SLIGHT_LEFT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CW_SLIGHT_LEFT = 37;
+    // Entrance and u-turn exit (e.g. "At the roundabout, take Nth exit") on a
+    // clockwise roundabout (as seen from above, typical for left-hand drive
+    // countries).
     ROUNDABOUT_ENTER_AND_EXIT_CW_U_TURN = 38;
 
-    // The following are entrance and exit (e.g. "At the roundabout, take Nth
-    // exit") on a counter-clockwise roundabout (as seen from above, typical
-    // for right-hand drive countries) where the exit is a particular turn
-    // amount (sharp right, vs. normal left, etc. - see the definitions for
-    // TURN_SHARP_LEFT, TURN_SLIGHT_RIGHT, etc., for a definition of what "sharp"
-    // vs. "normal" vs. "slight" is.
+    // Entrance and exit (e.g. "At the roundabout, take Nth exit") on a
+    // counter-clockwise roundabout (as seen from above, typical for right-hand
+    // drive countries).
     ROUNDABOUT_ENTER_AND_EXIT_CCW = 56;
+    // Entrance and sharp right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SHARP_RIGHT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SHARP_RIGHT = 39;
+    // Entrance and regular right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_NORMAL_RIGHT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_NORMAL_RIGHT = 40;
+    // Entrance and slight right turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SLIGHT_RIGHT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SLIGHT_RIGHT = 41;
+    // Entrance and straight exit (e.g. "At the roundabout, take Nth exit") on a
+    // counter-clockwise roundabout (as seen from above, typical for right-hand
+    // drive countries).
     ROUNDABOUT_ENTER_AND_EXIT_CCW_STRAIGHT = 42;
+    // Entrance and sharp left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SHARP_LEFT for the definition of
+    // sharp.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SHARP_LEFT = 43;
+    // Entrance and regular left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_NORMAL_LEFT for the definition of
+    // normal.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_NORMAL_LEFT = 44;
+    // Entrance and slight left turn exit (e.g. "At the roundabout, take Nth
+    // exit") on a counter-clockwise roundabout (as seen from above, typical for
+    // right-hand drive countries). See TURN_SLIGHT_LEFT for the definition of
+    // slight.
     ROUNDABOUT_ENTER_AND_EXIT_CCW_SLIGHT_LEFT = 45;
+    // Entrance and u-turn exit (e.g. "At the roundabout, take Nth exit") on a
+    // counter-clockwise roundabout (as seen from above, typical for right-hand
+    // drive countries).
     ROUNDABOUT_ENTER_AND_EXIT_CCW_U_TURN = 46;
 
     // Driver should steer straight.
@@ -224,10 +314,11 @@
     // Arrival to a destination where the direction is unknown.
     DESTINATION = 50;
 
-    // Arrival to a destination located in a particular direction (straight
-    // ahead, left side of the road, right side of the road).
+    // Arrival to a destination located straight ahead.
     DESTINATION_STRAIGHT = 51;
+    // Arrival to a destination located on the left side of the road.
     DESTINATION_LEFT = 52;
+    // Arrival to a destination located on the right side of the road.
     DESTINATION_RIGHT = 53;
   }
 
@@ -427,7 +518,8 @@
 // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
 // By restricting to that range, we ensure that we can convert to
 // and from  RFC 3339 date strings.
-// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
+// See
+// [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
 //
 // This is a subset of
 // https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto
@@ -534,3 +626,4 @@
   // Current status of the navigation.
   ServiceStatus service_status = 4;
 }
+
diff --git a/car-lib/src/android/car/user/CarUserManager.java b/car-lib/src/android/car/user/CarUserManager.java
index c3b00f3..1d684da 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -404,8 +404,9 @@
             UserIdentificationAssociationResponse response =
                     mService.getUserIdentificationAssociation(types);
             if (response != null) {
+                int[] values = response.getValues();
                 EventLog.writeEvent(EventLogTags.CAR_USER_MGR_GET_USER_AUTH_RESP,
-                        response.getValues().length);
+                        values != null ? values.length : 0);
             }
             return response;
         } catch (RemoteException e) {
diff --git a/car-lib/src/android/car/user/UserSwitchResult.java b/car-lib/src/android/car/user/UserSwitchResult.java
index 55e2dbc..1a4f5e9 100644
--- a/car-lib/src/android/car/user/UserSwitchResult.java
+++ b/car-lib/src/android/car/user/UserSwitchResult.java
@@ -67,7 +67,7 @@
     /**
      * When target user is same as current user.
      */
-    public static final int STATUS_ALREADY_REQUESTED_USER =
+    public static final int STATUS_OK_USER_ALREADY_IN_FOREGROUND =
             CommonResults.LAST_COMMON_STATUS + 1;
 
     /**
@@ -90,7 +90,7 @@
      *         {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
      *         {@link UserSwitchResult#STATUS_HAL_FAILURE},
      *         {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
-     *         {@link UserSwitchResult#STATUS_ALREADY_REQUESTED_USER},
+     *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
      *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
      *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
      *         {@link UserSwitchResult#STATUS_INVALID_REQUEST}.
@@ -107,7 +107,7 @@
      * Check if {@link UserSwitchResult} is successful.
      */
     public boolean isSuccess() {
-        return mStatus == STATUS_SUCCESSFUL || mStatus == STATUS_ALREADY_REQUESTED_USER;
+        return mStatus == STATUS_SUCCESSFUL || mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND;
     }
 
     // TODO(b/158195639): if you change any status constant, you need to manually assign its values
@@ -133,7 +133,7 @@
         STATUS_ANDROID_FAILURE,
         STATUS_HAL_FAILURE,
         STATUS_HAL_INTERNAL_FAILURE,
-        STATUS_ALREADY_REQUESTED_USER,
+        STATUS_OK_USER_ALREADY_IN_FOREGROUND,
         STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO,
         STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST,
         STATUS_INVALID_REQUEST
@@ -154,8 +154,8 @@
                     return "STATUS_HAL_FAILURE";
             case STATUS_HAL_INTERNAL_FAILURE:
                     return "STATUS_HAL_INTERNAL_FAILURE";
-            case STATUS_ALREADY_REQUESTED_USER:
-                    return "STATUS_ALREADY_REQUESTED_USER";
+            case STATUS_OK_USER_ALREADY_IN_FOREGROUND:
+                    return "STATUS_OK_USER_ALREADY_IN_FOREGROUND";
             case STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO:
                     return "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO";
             case STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST:
@@ -176,7 +176,7 @@
      *           {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
      *           {@link UserSwitchResult#STATUS_HAL_FAILURE},
      *           {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
-     *           {@link UserSwitchResult#STATUS_ALREADY_REQUESTED_USER},
+     *           {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
      *           {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
      *           {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
      *           {@link UserSwitchResult#STATUS_INVALID_REQUEST}.
@@ -201,7 +201,7 @@
      *         {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
      *         {@link UserSwitchResult#STATUS_HAL_FAILURE},
      *         {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
-     *         {@link UserSwitchResult#STATUS_ALREADY_REQUESTED_USER},
+     *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
      *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
      *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST}, or
      *         {@link UserSwitchResult#STATUS_INVALID_REQUEST}.
@@ -283,7 +283,7 @@
             time = 1590737883648L,
             codegenVersion = "1.0.15",
             sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserSwitchResult.java",
-            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_ALREADY_REQUESTED_USER\npublic static final  int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO\npublic static final  int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST\npublic static final  int STATUS_INVALID_REQUEST\nprivate final  int mStatus\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic  boolean isSuccess()\nclass UserSwitchResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+            inputSignatures = "public static final  int STATUS_SUCCESSFUL\npublic static final  int STATUS_ANDROID_FAILURE\npublic static final  int STATUS_HAL_FAILURE\npublic static final  int STATUS_HAL_INTERNAL_FAILURE\npublic static final  int STATUS_OK_USER_ALREADY_IN_FOREGROUND\npublic static final  int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO\npublic static final  int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST\npublic static final  int STATUS_INVALID_REQUEST\nprivate final  int mStatus\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic  boolean isSuccess()\nclass UserSwitchResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/car-usb-handler/res/values-te/strings.xml b/car-usb-handler/res/values-te/strings.xml
index a8dd520..25cd088 100644
--- a/car-usb-handler/res/values-te/strings.xml
+++ b/car-usb-handler/res/values-te/strings.xml
@@ -19,9 +19,7 @@
     <string name="app_name" msgid="6963366455471441257">"USB హ్యాండ్లర్‌"</string>
     <string name="usb_saved_devices" msgid="2829442070749964872">"సేవ్ చేసిన పరికరాలు"</string>
     <string name="usb_pref_delete_title" msgid="3885061814853467483">"USB పరికర కొరకు హాండీలింగ్ యాప్‌ని తొలగించండి"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for usb_pref_delete_message (5849493572520646218) -->
-    <skip />
+    <string name="usb_pref_delete_message" msgid="5849493572520646218">"%1$s‌ను ఆటోమేటిక్‌గా హ్యాండిల్ చేసే యాప్‌ను ఖచ్చితంగా తొలగించాలని మీరు అనుకుంటున్నారా?"</string>
     <string name="usb_pref_delete_yes" msgid="7803356145103146036">"అవును"</string>
     <string name="usb_pref_delete_cancel" msgid="5999791462730255929">"రద్దు చేయి"</string>
     <string name="usb_resolving_handlers" msgid="1943100136172948686">"మద్దతుగల హ్యాండ్లర్‌లను పొందడం"</string>
diff --git a/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background.xml b/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background.xml
new file mode 100644
index 0000000..cfab8bd
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true">
+        <ripple android:color="#2371cd">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+</selector>
diff --git a/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background_material.xml b/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background_material.xml
deleted file mode 100644
index cb36bb5..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/drawable-night/item_background_material.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="#2371cd">
-    <item android:id="@android:id/mask">
-        <color android:color="@android:color/white" />
-    </item>
-</ripple>
diff --git a/car_product/overlay/frameworks/base/core/res/res/drawable/item_background.xml b/car_product/overlay/frameworks/base/core/res/res/drawable/item_background.xml
new file mode 100644
index 0000000..b95802f
--- /dev/null
+++ b/car_product/overlay/frameworks/base/core/res/res/drawable/item_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true">
+        <ripple android:color="#4b9eff">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight">
+            <item android:id="@android:id/mask">
+                <color android:color="@android:color/white" />
+            </item>
+        </ripple>
+    </item>
+</selector>
diff --git a/car_product/overlay/frameworks/base/core/res/res/drawable/item_background_material.xml b/car_product/overlay/frameworks/base/core/res/res/drawable/item_background_material.xml
deleted file mode 100644
index 9311499..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/drawable/item_background_material.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="#4b9eff">
-    <item android:id="@android:id/mask">
-        <color android:color="@android:color/white" />
-    </item>
-</ripple>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_button_bar_material.xml b/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_button_bar_material.xml
deleted file mode 100644
index b227bec..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_button_bar_material.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:id="@*android:id/buttonPanel"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:scrollbarAlwaysDrawVerticalTrack="true"
-            android:scrollIndicators="top|bottom"
-            android:fillViewport="true"
-            style="?android:attr/buttonBarStyle">
-    <com.android.internal.widget.ButtonBarLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingStart="@*android:dimen/button_bar_layout_start_padding"
-        android:paddingEnd="@*android:dimen/button_bar_layout_end_padding"
-        android:paddingTop="@*android:dimen/button_bar_layout_top_padding"
-        android:layoutDirection="locale"
-        android:orientation="horizontal"
-        android:gravity="left|center_vertical">
-
-        <Button
-            android:id="@*android:id/button3"
-            style="@*android:style/CarAction1"
-            android:background="@*android:drawable/car_dialog_button_background"
-            android:layout_marginRight="@*android:dimen/button_end_margin"
-            android:layout_width="wrap_content"
-            android:layout_height="@*android:dimen/button_layout_height" />
-
-        <Button
-            android:id="@*android:id/button2"
-            style="@*android:style/CarAction1"
-            android:background="@*android:drawable/car_dialog_button_background"
-            android:layout_marginRight="@*android:dimen/button_end_margin"
-            android:layout_width="wrap_content"
-            android:layout_height="@*android:dimen/button_layout_height" />
-
-        <Button
-            android:id="@*android:id/button1"
-            style="@*android:style/CarAction1"
-            android:background="@*android:drawable/car_dialog_button_background"
-            android:layout_width="wrap_content"
-            android:layout_height="@*android:dimen/button_layout_height" />
-        <Space
-            android:id="@*android:id/spacer"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:visibility="invisible" />
-    </com.android.internal.widget.ButtonBarLayout>
-</ScrollView>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_material.xml b/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_material.xml
deleted file mode 100644
index 7452026..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_material.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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.internal.widget.AlertDialogLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@*android:id/parentPanel"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="start|top"
-    android:orientation="vertical">
-
-    <include layout="@*android:layout/alert_dialog_title_material" />
-
-    <FrameLayout
-        android:id="@*android:id/contentPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dp">
-
-        <ScrollView
-            android:id="@*android:id/scrollView"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:clipToPadding="false">
-
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
-
-                <Space
-                    android:id="@*android:id/textSpacerNoTitle"
-                    android:visibility="gone"
-                    android:layout_width="match_parent"
-                    android:layout_height="@*android:dimen/dialog_no_title_padding_top" />
-
-                <TextView
-                    android:id="@*android:id/message"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="@*android:dimen/text_view_start_margin"
-                    android:layout_marginEnd="@*android:dimen/text_view_end_margin"
-                    style="@*android:style/CarBody2"/>
-
-                <!-- we don't need this spacer, but the id needs to be here for compatibility -->
-                <Space
-                    android:id="@*android:id/textSpacerNoButtons"
-                    android:visibility="gone"
-                    android:layout_width="match_parent"
-                    android:layout_height="0dp" />
-            </LinearLayout>
-        </ScrollView>
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@*android:id/customPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dp">
-
-        <FrameLayout
-            android:id="@*android:id/custom"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-    </FrameLayout>
-
-    <include
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        layout="@*android:layout/alert_dialog_button_bar_material" />
-</com.android.internal.widget.AlertDialogLayout>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_title_material.xml b/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_title_material.xml
deleted file mode 100644
index 92bd7d0..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/alert_dialog_title_material.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@*android:id/topPanel"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:gravity="center_vertical"
-              android:orientation="vertical">
-
-    <!-- If the client uses a customTitle, it will be added here. -->
-
-    <RelativeLayout
-        android:id="@*android:id/title_template"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/car_card_header_height"
-        android:orientation="horizontal">
-
-        <ImageView
-            android:id="@*android:id/icon"
-            android:layout_width="@*android:dimen/image_size"
-            android:layout_height="@*android:dimen/image_size"
-            android:layout_marginStart="@*android:dimen/image_margin_start"
-            android:layout_alignParentStart="true"
-            android:layout_centerVertical="true"
-            android:scaleType="fitCenter"
-            android:src="@null" />
-
-        <com.android.internal.widget.DialogTitle
-            android:id="@*android:id/alertTitle"
-            android:maxLines="1"
-            android:ellipsize="none"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_toEndOf="@*android:id/icon"
-            android:textAlignment="viewStart"
-            android:layout_centerVertical="true"
-            android:layout_marginStart="@*android:dimen/text_view_start_margin"
-            android:layout_marginEnd="@*android:dimen/text_view_end_margin"
-            style="?android:attr/windowTitleStyle" />
-    </RelativeLayout>
-
-    <Space
-        android:id="@*android:id/titleDividerNoCustom"
-        android:visibility="gone"
-        android:layout_width="match_parent"
-        android:layout_height="0dp" />
-</LinearLayout>
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_action.xml b/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_action.xml
deleted file mode 100644
index 5604049..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_action.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 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
-  -->
-<Button
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-    android:id="@*android:id/action0"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
-    android:layout_gravity="center"
-    android:fontFamily="sans-serif"
-    android:gravity="start|center_vertical"
-    android:layout_marginStart="0dp"
-    android:textColor="@*android:color/notification_default_color"
-    android:textSize="@*android:dimen/notification_text_size"
-    android:textStyle="normal"
-    android:singleLine="true"
-    android:ellipsize="end"
-    android:paddingStart="@*android:dimen/notification_content_margin_start"
-    android:paddingEnd="@*android:dimen/notification_content_margin_start"
-    android:background="@*android:drawable/notification_material_action_background" />
diff --git a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_media_action.xml b/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_media_action.xml
deleted file mode 100644
index b6468df..0000000
--- a/car_product/overlay/frameworks/base/core/res/res/layout/notification_material_media_action.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<ImageButton
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@android:style/Widget.Material.Button.Borderless.Small"
-    android:id="@*android:id/action0"
-    android:background="@*android:drawable/notification_material_media_action_background"
-    android:layout_width="0dp"
-    android:layout_height="@*android:dimen/media_notification_action_button_size"
-    android:layout_weight="1"
-    android:padding="0dp"
-    android:gravity="center"
-    android:scaleType="fitCenter" />
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/colors.xml b/car_product/overlay/frameworks/base/core/res/res/values/colors.xml
index e2717e5..94a0478 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/colors.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/colors.xml
@@ -33,9 +33,6 @@
     <!-- The secondary text color if the text is on top of a dark background. -->
     <color name="notification_secondary_text_color_dark">@*android:color/car_body2</color>
 
-    <!-- The background color of a notification card. -->
-    <color name="notification_material_background_color">@*android:color/car_colorPrimary</color>
-
     <!-- The default color for text in a notification. This color is also the default color for
          icons. -->
     <color name="notification_default_color">@*android:color/car_accent</color>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml b/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml
index be7e15a..08ea8dc 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/styles_device_default.xml
@@ -141,4 +141,9 @@
         <item name="android:layout">@*android:layout/car_preference</item>
     </style>
 
+    <!-- AlertDialog Style -->
+    <style name="AlertDialog.DeviceDefault" parent="*android:AlertDialog.Material">
+        <item name="android:layout">@*android:layout/car_alert_dialog</item>
+    </style>
+
 </resources>
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml b/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml
index 98b52dd..5796cff 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/themes_device_defaults.xml
@@ -34,6 +34,7 @@
         <item name="android:colorForeground">@*android:color/car_card_light</item>
         <item name="android:editTextColor">@*android:color/car_body1</item>
         <item name="android:listPreferredItemHeightSmall">@*android:dimen/car_single_line_list_item_height</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorHint">@*android:color/car_body2</item>
         <item name="android:textColorPrimary">@*android:color/text_color_primary</item>
         <item name="android:textColorSecondary">@*android:color/car_body2</item>
@@ -66,6 +67,7 @@
         <item name="android:colorPrimaryDark">@*android:color/primary_device_default_dark</item>
         <item name="android:colorForeground">@*android:color/car_card_light</item>
         <item name="android:editTextColor">@*android:color/car_body1</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorHint">@*android:color/car_body2</item>
         <item name="android:textColorPrimary">@*android:color/text_color_primary</item>
         <item name="android:textColorSecondary">@*android:color/car_body2</item>
@@ -82,6 +84,7 @@
         <item name="android:textAppearanceMedium">@*android:style/TextAppearance.DeviceDefault.Medium</item>
         <item name="android:textAppearanceSmall">@*android:style/TextAppearance.DeviceDefault.Small</item>
         <item name="android:textAppearanceButton">@*android:style/Widget.DeviceDefault.Button</item>
+        <item name="android:alertDialogStyle">@*android:style/AlertDialog.DeviceDefault</item>
         <item name="android:borderlessButtonStyle">@*android:style/Widget.DeviceDefault.Button.Borderless.Colored</item>
         <item name="android:buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
         <item name="android:buttonStyle">@*android:style/Widget.DeviceDefault.Button</item>
@@ -94,6 +97,7 @@
         <item name="android:colorPrimaryDark">@*android:color/primary_device_default_dark</item>
         <item name="android:colorForeground">@*android:color/car_card_light</item>
         <item name="android:editTextColor">@*android:color/car_body1</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorHint">@*android:color/car_body2</item>
         <item name="android:textColorPrimary">@*android:color/text_color_primary</item>
         <item name="android:textColorSecondary">@*android:color/car_body2</item>
@@ -127,6 +131,7 @@
         <item name="android:colorAccent">@*android:color/accent_device_default_light</item>
         <item name="android:colorBackground">@*android:color/primary_device_default_light</item>
         <item name="android:listDivider">@*android:color/car_keyboard_divider_line</item>
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
         <item name="android:textColorPrimary">@*android:color/car_keyboard_text_primary_color</item>
         <item name="android:textColorSecondary">@*android:color/car_keyboard_text_secondary_color</item>
     </style>
@@ -188,6 +193,10 @@
         <item name="android:textAppearanceListItem">@android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSmall">@android:style/TextAppearance.DeviceDefault.Large</item>
         <item name="android:textAppearanceListItemSecondary">@android:style/TextAppearance.DeviceDefault.Small</item>
+
+        <!-- Icon sizes -->
+        <item name="*android:iconfactoryIconSize">@*android:dimen/resolver_icon_size</item>
+        <item name="*android:iconfactoryBadgeSize">@*android:dimen/resolver_badge_size</item>
     </style>
 
 
@@ -285,6 +294,8 @@
         <!-- Hide action bar -->
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
+
+        <item name="android:selectableItemBackground">@*android:drawable/item_background</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Panel" parent="android:Theme.DeviceDefault.Panel"/>
diff --git a/evs/sampleDriver/EvsEnumerator.cpp b/evs/sampleDriver/EvsEnumerator.cpp
index ef6009e..2dbedb4 100644
--- a/evs/sampleDriver/EvsEnumerator.cpp
+++ b/evs/sampleDriver/EvsEnumerator.cpp
@@ -280,6 +280,10 @@
 
     // Is this a recognized camera id?
     CameraRecord *pRecord = findCameraById(cameraId);
+    if (pRecord == nullptr) {
+        LOG(ERROR) << cameraId << " does not exist!";
+        return nullptr;
+    }
 
     // Has this camera already been instantiated by another caller?
     sp<EvsV4lCamera> pActiveCamera = pRecord->activeInstance.promote();
diff --git a/evs/sampleDriver/resources/evs_sample_configuration.xml b/evs/sampleDriver/resources/evs_sample_configuration.xml
index fa3ada3..b07d193 100644
--- a/evs/sampleDriver/resources/evs_sample_configuration.xml
+++ b/evs/sampleDriver/resources/evs_sample_configuration.xml
@@ -199,6 +199,221 @@
         </device>
     </camera>
 
+    <!-- camera device information for v4l2loopback devices -->
+    <camera>
+        <!-- camera group v4l2loopback_group0 -->
+        <group id='v4l2loopback_group0' synchronized='CALIBRATED'>
+            <caps>
+                <!-- list of stream configuration supported by all physical devices -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <parameter
+                    name='REQUEST_AVAILABLE_CAPABILITIES'
+                    type='enum'
+                    size='1'
+                    value='LOGICAL_MULTI_CAMERA'
+                />
+                <parameter
+                    name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+                    type='byte[]'
+                    size='4'
+                    value='/dev/video90,/dev/video91,/dev/video92,/dev/video93'
+                />
+            </characteristics>
+        </group>
+
+        <!-- camera device starts  -->
+        <!-- /dev/video9[0-9]$ were reserved for experimental purposes with v4l2loopback devices -->
+        <!-- The following calibration parameters are for the sample camera images in packages/services/Car/surround_view/service-impl/test_data/ -->
+        <device id='/dev/video90' position='front'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.03711481733589263,-0.0014805627895442888,-0.00030212056866592464,-0.00020149538570397933,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='608.0026093794693,608.205469489769,968.699544102168,476.38843298898996,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='-7.8028875403817685e-02,1.4537396465103221e+00,-8.4197165554645001e-02'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.9049874,0.0153074,-0.0088196,0.4250714'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video91' position='right'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.040116809827977926,0.0028769489398543014,-0.002651039958977229,0.00024260630476736675,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='607.8691721095306,608.0112887189435,975.5686146375716,481.1938786570715,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='2.9715052384687407e-01,1.1407102692699396e+00,3.0074545273489206e-01'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.6293863,-0.6544242,0.2967697,0.2958542'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video92' position='rear'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.03998488563470043,0.0024786686909103388,-0.002354736769480817,0.00018369619088506146,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='608.557299289448,608.8093878512448,960.1949354417656,474.74744054048256,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='1.7115269161259747e-01,1.4376160762596599e+00,-1.9028844233159006e-02'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='-0.0341381,-0.9101571,0.4126677,0.0124103'
+                />
+            </characteristics>
+        </device>
+        <device id='/dev/video93' position='left'>
+            <caps>
+                <!-- list of supported stream configurations -->
+                <stream id='0' width='1920' height='1024' format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Lens distortion information. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_DISTORTION
+                -->
+                <parameter
+                    name='LENS_DISTORTION'
+                    type='float'
+                    size='5'
+                    value='-0.038096507459563965,0.0004008114278766646,-0.0013549275607082035,-5.9961182248325556e-06,0.0'
+                />
+
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='608.1221963545495,608.0523818661524,943.6280444638576,474.8564698210861,0.0'
+                />
+
+                <!-- Camera pose translation and rotation.  See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_TRANSLATION
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_POSE_ROTATION
+                -->
+                <parameter
+                    name='LENS_POSE_TRANSLATION'
+                    type='float'
+                    size='3'
+                    value='-3.0842691427126512e-01,1.0884122033556984e+00,3.4419058255954926e-01'
+                />
+                <parameter
+                    name='LENS_POSE_ROTATION'
+                    type='float'
+                    size='4'
+                    value='0.612825,0.6634091,-0.3112416,0.2957406'
+                />
+            </characteristics>
+        </device>
+    </camera>
+
     <!-- display device starts -->
     <display>
         <device id='display0' position='driver'>
diff --git a/service/src/com/android/car/CarPropertyService.java b/service/src/com/android/car/CarPropertyService.java
index 9f7bd2b..905ca74 100644
--- a/service/src/com/android/car/CarPropertyService.java
+++ b/service/src/com/android/car/CarPropertyService.java
@@ -168,6 +168,29 @@
 
     @Override
     public void dump(PrintWriter writer) {
+        writer.println("*CarPropertyService*");
+        synchronized (mLock) {
+            writer.println("    Listener is set for PropertyHalService: " + mListenerIsSet);
+            writer.println("    There are " + mClientMap.size() + " clients "
+                    + "using CarPropertyService.");
+            writer.println("    Properties registered: ");
+            for (int propId : mPropIdClientMap.keySet()) {
+                writer.println("        propId: 0x" + toHexString(propId)
+                        + " is registered by " + mPropIdClientMap.get(propId).size()
+                        + " client(s).");
+            }
+            writer.println("    Properties changed by CarPropertyService: ");
+            for (int i = 0; i < mSetOperationClientMap.size(); i++) {
+                int propId = mSetOperationClientMap.keyAt(i);
+                SparseArray areaIdToClient = mSetOperationClientMap.valueAt(i);
+                for (int j = 0; j < areaIdToClient.size(); j++) {
+                    int areaId = areaIdToClient.keyAt(j);
+                    writer.println("        propId: 0x" + toHexString(propId)
+                            + " areaId: 0x" + toHexString(areaId)
+                            + " by client: " + areaIdToClient.valueAt(j));
+                }
+            }
+        }
     }
 
     @Override
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index 0a8c420..ed3dcce 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -398,12 +398,20 @@
         pw.printf("\t%s [occupantZoneId]\n", COMMAND_RESET_USER_ID_IN_OCCUPANT_ZONE);
         pw.println("\t  Unmaps the user assigned to occupant zone id.");
 
+        pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 [..TYPE_N]\n",
+                COMMAND_GET_USER_AUTH_ASSOCIATION);
+        pw.println("\t  Gets the N user authentication values for the N types for the given user");
+        pw.println("\t  (or current user when not specified).");
+        pw.println("\t  By defautt it calls CarUserManager, but using --hal-only will call just "
+                + "UserHalService.");
+
         pw.printf("\t%s [--hal-only] [--user USER_ID] TYPE1 VALUE1 [..TYPE_N VALUE_N]\n",
                 COMMAND_SET_USER_AUTH_ASSOCIATION);
         pw.println("\t  Sets the N user authentication types with the N values for the given user");
         pw.println("\t  (or current user when not specified).");
         pw.println("\t  By defautt it calls CarUserManager, but using --hal-only will call just "
                 + "UserHalService.");
+
         pw.printf("\t  %s\n", VALID_USER_AUTH_TYPES_HELP);
         pw.printf("\t  %s\n", VALID_USER_AUTH_SET_VALUES_HELP);
     }
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
index b122a29..acf26c4 100644
--- a/service/src/com/android/car/hal/UserHalService.java
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -250,12 +250,12 @@
     }
 
     @GuardedBy("mLock")
-    private void checkSupportedLocked() {
+    private void checkSupported() {
         Preconditions.checkState(isSupported(), UNSUPPORTED_MSG);
     }
 
     @GuardedBy("mLock")
-    private void checkUserAssociationSupportedLocked() {
+    private void checkUserAssociationSupported() {
         Preconditions.checkState(isUserAssociationSupported(), USER_ASSOCIATION_UNSUPPORTED_MSG);
     }
 
@@ -279,16 +279,15 @@
         Objects.requireNonNull(usersInfo);
         UserHalHelper.checkValid(usersInfo);
         Objects.requireNonNull(callback);
+        checkSupported();
 
-        VehiclePropValue propRequest;
-        int requestId;
+        int requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.createPropRequest(INITIAL_USER_INFO, requestId,
+                requestType);
+        UserHalHelper.addUsersInfo(propRequest, usersInfo);
+
         synchronized (mLock) {
-            checkSupportedLocked();
             if (hasPendingRequestLocked(InitialUserInfoResponse.class, callback)) return;
-            requestId = getNextRequestId();
-            propRequest = UserHalHelper.createPropRequest(INITIAL_USER_INFO, requestId,
-                    requestType);
-            UserHalHelper.addUsersInfo(propRequest, usersInfo);
             addPendingRequestLocked(requestId, InitialUserInfoResponse.class, callback);
         }
 
@@ -354,26 +353,25 @@
         Objects.requireNonNull(request, "request cannot be null");
         if (DBG) Log.d(TAG, "switchUser(" + request + ")");
 
-        VehiclePropValue propRequest;
-        int requestId;
+        checkSupported();
+        request.requestId = getNextRequestId();
+        request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
         synchronized (mLock) {
-            checkSupportedLocked();
             if (hasPendingRequestLocked(SwitchUserResponse.class, callback)) return;
-            requestId = getNextRequestId();
-            request.requestId = requestId;
-            request.messageType = SwitchUserMessageType.ANDROID_SWITCH;
-            propRequest = UserHalHelper.toVehiclePropValue(request);
-            addPendingRequestLocked(requestId, SwitchUserResponse.class, callback);
+            addPendingRequestLocked(request.requestId, SwitchUserResponse.class, callback);
         }
 
-        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_REQ, requestId,
+        EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SWITCH_USER_REQ, request.requestId,
                 request.targetUser.userId, timeoutMs);
-        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED, requestId,
+        CarStatsLog.write(CarStatsLog.CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED, request.requestId,
                 CarStatsLog
                 .CAR_USER_HAL_MODIFY_USER_REQUEST_REPORTED__REQUEST_TYPE__SWITCH_REQUEST_ANDROID,
                 request.usersInfo.currentUser.userId, request.usersInfo.currentUser.flags,
                 request.targetUser.userId, request.targetUser.flags, timeoutMs);
-        sendHalRequest(requestId, timeoutMs, propRequest, callback);
+
+        sendHalRequest(request.requestId, timeoutMs, propRequest, callback);
     }
 
     /**
@@ -386,12 +384,9 @@
         Objects.requireNonNull(request, "request cannot be null");
         if (DBG) Log.d(TAG, "removeUser(" + request + ")");
 
-        VehiclePropValue propRequest;
-        synchronized (mLock) {
-            checkSupportedLocked();
-            request.requestId = getNextRequestId();
-            propRequest = UserHalHelper.toVehiclePropValue(request);
-        }
+        checkSupported();
+        request.requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
 
         EventLog.writeEvent(EventLogTags.CAR_USER_HAL_REMOVE_USER_REQ,
                 request.removedUserInfo.userId, request.usersInfo.currentUser.userId);
@@ -426,12 +421,12 @@
         Objects.requireNonNull(callback);
         if (DBG) Log.d(TAG, "createUser(): req=" + request + ", timeout=" + timeoutMs);
 
-        VehiclePropValue propRequest;
+        checkSupported();
+        request.requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
         synchronized (mLock) {
-            checkSupportedLocked();
             if (hasPendingRequestLocked(CreateUserResponse.class, callback)) return;
-            request.requestId = getNextRequestId();
-            propRequest = UserHalHelper.toVehiclePropValue(request);
             addPendingRequestLocked(request.requestId, CreateUserResponse.class, callback);
         }
 
@@ -453,12 +448,9 @@
         Objects.requireNonNull(request, "request cannot be null");
         if (DBG) Log.d(TAG, "postSwitchResponse(" + request + ")");
 
-        VehiclePropValue propRequest;
-        synchronized (mLock) {
-            checkSupportedLocked();
-            request.messageType = SwitchUserMessageType.ANDROID_POST_SWITCH;
-            propRequest = UserHalHelper.toVehiclePropValue(request);
-        }
+        checkSupported();
+        request.messageType = SwitchUserMessageType.ANDROID_POST_SWITCH;
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
 
         EventLog.writeEvent(EventLogTags.CAR_USER_HAL_POST_SWITCH_USER_REQ, request.requestId,
                 request.targetUser.userId, request.usersInfo.currentUser.userId);
@@ -484,13 +476,10 @@
         Objects.requireNonNull(request, "request cannot be null");
         if (DBG) Log.d(TAG, "userSwitchLegacy(" + request + ")");
 
-        VehiclePropValue propRequest;
-        synchronized (mLock) {
-            checkSupportedLocked();
-            request.requestId = getNextRequestId();
-            request.messageType = SwitchUserMessageType.LEGACY_ANDROID_SWITCH;
-            propRequest = UserHalHelper.toVehiclePropValue(request);
-        }
+        checkSupported();
+        request.requestId = getNextRequestId();
+        request.messageType = SwitchUserMessageType.LEGACY_ANDROID_SWITCH;
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
 
         EventLog.writeEvent(EventLogTags.CAR_USER_HAL_LEGACY_SWITCH_USER_REQ, request.requestId,
                 request.targetUser.userId, request.usersInfo.currentUser.userId);
@@ -523,9 +512,7 @@
     public UserIdentificationResponse getUserAssociation(
             @NonNull UserIdentificationGetRequest request) {
         Objects.requireNonNull(request, "request cannot be null");
-        synchronized (mLock) {
-            checkUserAssociationSupportedLocked();
-        }
+        checkUserAssociationSupported();
 
         // Check that it doesn't have dupes
         SparseBooleanArray types = new SparseBooleanArray(request.numberAssociationTypes);
@@ -629,14 +616,14 @@
             types.put(type, true);
         }
 
-        VehiclePropValue propRequest;
-        int requestId;
+        checkUserAssociationSupported();
+        request.requestId = getNextRequestId();
+        VehiclePropValue propRequest = UserHalHelper.toVehiclePropValue(request);
+
         synchronized (mLock) {
-            checkUserAssociationSupportedLocked();
             if (hasPendingRequestLocked(UserIdentificationResponse.class, callback)) return;
-            requestId = request.requestId = getNextRequestId();
-            propRequest = UserHalHelper.toVehiclePropValue(request);
-            addPendingRequestLocked(requestId, UserIdentificationResponse.class, request, callback);
+            addPendingRequestLocked(request.requestId, UserIdentificationResponse.class, request,
+                    callback);
         }
 
         EventLog.writeEvent(EventLogTags.CAR_USER_HAL_SET_USER_AUTH_REQ,
@@ -650,11 +637,11 @@
             associationValues[i] = association.value;
         }
         CarStatsLog.write(CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED,
-                requestId,
+                request.requestId,
                 CarStatsLog.CAR_USER_HAL_USER_ASSOCIATION_REQUEST_REPORTED__REQUEST_TYPE__SET,
                 request.userInfo.userId, request.userInfo.flags, request.numberAssociations,
                 Arrays.toString(associationTypes), Arrays.toString(associationValues));
-        sendHalRequest(requestId, timeoutMs, propRequest, callback);
+        sendHalRequest(request.requestId, timeoutMs, propRequest, callback);
     }
 
     private void handleOnUserIdentificationAssociation(@NonNull VehiclePropValue value) {
@@ -756,7 +743,7 @@
     @VisibleForTesting
     int getNextRequestId() {
         synchronized (mLock) {
-            return ++mNextRequestId;
+            return mNextRequestId++;
         }
     }
 
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index b9c54a0..fd469e7 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -763,7 +763,7 @@
      * Corner cases:
      * <ul>
      *   <li> If target user is already the current user, no user switch is performed and receiver
-     *   would receive {@code STATUS_ALREADY_REQUESTED_USER} right away.
+     *   would receive {@code STATUS_OK_USER_ALREADY_IN_FOREGROUND} right away.
      *   <li> If HAL user switch call fails, no Android user switch. Receiver would receive
      *   {@code STATUS_HAL_INTERNAL_FAILURE}.
      *   <li> If HAL user switch call is successful, but android user switch call fails,
@@ -795,7 +795,7 @@
             if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
                 Log.d(TAG_USER, "Current user is same as requested target user: " + targetUserId);
             }
-            int resultStatus = UserSwitchResult.STATUS_ALREADY_REQUESTED_USER;
+            int resultStatus = UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND;
             sendUserSwitchResult(receiver, resultStatus);
             return;
         }
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
index 02da338..e2017a8 100644
--- a/surround_view/service-impl/Android.bp
+++ b/surround_view/service-impl/Android.bp
@@ -38,8 +38,47 @@
         "libutils",
     ],
     required: [
-        "VolvoXC40_low.obj",
-        "VolvoXC40_low.mtl",
+        "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",
     ],
 }
 
@@ -116,6 +155,8 @@
     name : "android.automotive.sv.service@1.0-impl",
     vendor : true,
     srcs : [
+        "AnimationModule.cpp",
+        "CameraUtils.cpp",
         "CoreLibSetupHelper.cpp",
         "SurroundViewService.cpp",
         "SurroundView2dSession.cpp",
@@ -137,6 +178,7 @@
         "libhardware",
         "libhidlbase",
         "libhidlmemory",
+        "libio_module",
         "libui",
         "libutils",
     ],
@@ -189,35 +231,56 @@
 
 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", src : "test_data/3.png", sub_dir : "automotive/sv",
+    name :"cam3.png",
+    soc_specific : true,
+    src : "test_data/3.png",
+    sub_dir : "automotive/sv",
 }
 
 prebuilt_etc {
-    name: "cube.obj",
-    src: "test_data/cube.obj",
+    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: "cube.mtl",
-    src: "test_data/cube.mtl",
-    sub_dir: "automotive/sv",
+    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/surround_view/service-impl/AnimationModule.cpp b/surround_view/service-impl/AnimationModule.cpp
index ae9eb3f..2f540e4 100644
--- a/surround_view/service-impl/AnimationModule.cpp
+++ b/surround_view/service-impl/AnimationModule.cpp
@@ -119,10 +119,16 @@
 
 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 = part.second.child_part_ids,
+                                                          .childIds = childIds,
                                                           .parentModel = gMat4Identity,
                                                           .localModel = gMat4Identity,
                                                           .currentModel = gMat4Identity,
diff --git a/surround_view/service-impl/AnimationModule.h b/surround_view/service-impl/AnimationModule.h
index 52845ac..de8dd35 100644
--- a/surround_view/service-impl/AnimationModule.h
+++ b/surround_view/service-impl/AnimationModule.h
@@ -17,6 +17,7 @@
 #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>
@@ -37,206 +38,6 @@
 namespace V1_0 {
 namespace implementation {
 
-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;
-
-    // Car part pose w.r.t parent's coordinate.
-    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;
-};
-
 // Car animation class. It is constructed with textures, animations, and
 // vhal_handler. It automatically updates animation params when
 // GetUpdatedAnimationParams() is called.
diff --git a/surround_view/service-impl/CameraUtils.cpp b/surround_view/service-impl/CameraUtils.cpp
new file mode 100644
index 0000000..0dd6226
--- /dev/null
+++ b/surround_view/service-impl/CameraUtils.cpp
@@ -0,0 +1,296 @@
+/*
+ * 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/surround_view/service-impl/CameraUtils.h b/surround_view/service-impl/CameraUtils.h
new file mode 100644
index 0000000..1fbc8d4
--- /dev/null
+++ b/surround_view/service-impl/CameraUtils.h
@@ -0,0 +1,71 @@
+/*
+ * 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/surround_view/service-impl/CarModelConfigReader.cpp b/surround_view/service-impl/CarModelConfigReader.cpp
new file mode 100644
index 0000000..5bfb0a6
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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 "IOModule"
+
+#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/surround_view/service-impl/CarModelConfigReader.h b/surround_view/service-impl/CarModelConfigReader.h
new file mode 100644
index 0000000..c2e9049
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.h
@@ -0,0 +1,42 @@
+/*
+ * 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/surround_view/service-impl/CarModelConfigReaderTests.cpp b/surround_view/service-impl/CarModelConfigReaderTests.cpp
new file mode 100644
index 0000000..916002b
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReaderTests.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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/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(), 2);
+        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/surround_view/service-impl/ConfigReader.cpp b/surround_view/service-impl/ConfigReader.cpp
new file mode 100644
index 0000000..674bf7b
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.cpp
@@ -0,0 +1,267 @@
+/*
+ * 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 "IOModule"
+
+#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));
+        }
+    }
+    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/surround_view/service-impl/ConfigReader.h b/surround_view/service-impl/ConfigReader.h
new file mode 100644
index 0000000..7bdbe2a
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.h
@@ -0,0 +1,42 @@
+/*
+ * 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/surround_view/service-impl/ConfigReaderTests.cpp b/surround_view/service-impl/ConfigReaderTests.cpp
new file mode 100644
index 0000000..ef51a5f
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderTests.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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/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/video90");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[1], "/dev/video91");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[2], "/dev/video92");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[3], "/dev/video93");
+
+    // Masks
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames.size(), 4);
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[0], "/vendor/mask_front.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[1], "/vendor/mask_right.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[2], "/vendor/mask_rear.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[3], "/vendor/mask_left.png");
+
+    // Surround view 2D
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dEnabled, true);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.width, 600);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.height, 900);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.width, 6.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.height, 9.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.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, 6.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_divisions, 20);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_height, 5.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_divisions, 30);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.angular_divisions, 50);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_coefficient, 2.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/surround_view/service-impl/ConfigReaderUtil.cpp b/surround_view/service-impl/ConfigReaderUtil.cpp
new file mode 100644
index 0000000..553108e
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "IOModule"
+
+#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/surround_view/service-impl/ConfigReaderUtil.h b/surround_view/service-impl/ConfigReaderUtil.h
new file mode 100644
index 0000000..030cc0f
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.h
@@ -0,0 +1,65 @@
+/*
+ * 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/surround_view/service-impl/IOModule.cpp b/surround_view/service-impl/IOModule.cpp
new file mode 100644
index 0000000..3ab644b
--- /dev/null
+++ b/surround_view/service-impl/IOModule.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "IOModule"
+
+#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/surround_view/service-impl/IOModule.h b/surround_view/service-impl/IOModule.h
new file mode 100644
index 0000000..2e19dc5
--- /dev/null
+++ b/surround_view/service-impl/IOModule.h
@@ -0,0 +1,57 @@
+/*
+ * 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/surround_view/service-impl/IOModuleCommon.h b/surround_view/service-impl/IOModuleCommon.h
new file mode 100644
index 0000000..5550fd5
--- /dev/null
+++ b/surround_view/service-impl/IOModuleCommon.h
@@ -0,0 +1,354 @@
+/*
+ * 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/surround_view/service-impl/MathHelp.h b/surround_view/service-impl/MathHelp.h
index fa20af6..6623594 100644
--- a/surround_view/service-impl/MathHelp.h
+++ b/surround_view/service-impl/MathHelp.h
@@ -28,6 +28,8 @@
 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,
diff --git a/surround_view/service-impl/MtlReader.cpp b/surround_view/service-impl/MtlReader.cpp
index d86a15a..3d8bf8c 100644
--- a/surround_view/service-impl/MtlReader.cpp
+++ b/surround_view/service-impl/MtlReader.cpp
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "IOModule"
+
 #include "MtlReader.h"
 
 #include <android-base/logging.h>
 #include <cstdio>
 
-#define LOG_TAG "MtlReader"
-
 namespace android {
 namespace hardware {
 namespace automotive {
diff --git a/surround_view/service-impl/ObjReader.cpp b/surround_view/service-impl/ObjReader.cpp
index 174ef5b..5473287 100644
--- a/surround_view/service-impl/ObjReader.cpp
+++ b/surround_view/service-impl/ObjReader.cpp
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "IOModule"
+
 #include "ObjReader.h"
 
 #include <array>
diff --git a/surround_view/service-impl/SurroundView2dSession.cpp b/surround_view/service-impl/SurroundView2dSession.cpp
index 4ff62fb..c5b7894 100644
--- a/surround_view/service-impl/SurroundView2dSession.cpp
+++ b/surround_view/service-impl/SurroundView2dSession.cpp
@@ -26,6 +26,8 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 
+#include "CameraUtils.h"
+
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::android::hardware::camera::device::V3_2::Stream;
 
@@ -73,6 +75,15 @@
     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 {};
+        }
+    }
+
     if (buffers.size() != kNumFrames) {
         LOG(ERROR) << "The number of incoming frames is " << buffers.size()
                    << ", which is different from the number " << kNumFrames
@@ -95,7 +106,7 @@
     // Notify the session that a new set of frames is ready
     {
         scoped_lock<mutex> lock(mSession->mAccessLock);
-        mSession->mFramesAvailable = true;
+        mSession->mProcessingEvsFrames = true;
     }
     mSession->mFramesSignal.notify_all();
 
@@ -208,9 +219,7 @@
                 break;
             }
 
-            mFramesSignal.wait(lock, [this]() {
-                return mFramesAvailable;
-            });
+            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
         }
 
         handleFrames(mSequenceId);
@@ -218,7 +227,7 @@
         {
             // Set the boolean to false to receive the next set of frames.
             scoped_lock<mutex> lock(mAccessLock);
-            mFramesAvailable = false;
+            mProcessingEvsFrames = false;
         }
     }
 
@@ -234,8 +243,10 @@
     }
 }
 
-SurroundView2dSession::SurroundView2dSession(sp<IEvsEnumerator> pEvs)
+SurroundView2dSession::SurroundView2dSession(sp<IEvsEnumerator> pEvs,
+                                             IOModuleConfig* pConfig)
     : mEvs(pEvs),
+      mIOModuleConfig(pConfig),
       mStreamState(STOPPED) {
     mEvsCameraIds = {"0", "1", "2", "3"};
 }
@@ -286,6 +297,7 @@
     // 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;
@@ -318,7 +330,7 @@
     LOG(DEBUG) << __FUNCTION__;
     scoped_lock <mutex> lock(mAccessLock);
 
-    framesRecord.inUse = false;
+    mFramesRecord.inUse = false;
 
     (void)svFramesDesc;
     return {};
@@ -363,48 +375,54 @@
     return {};
 }
 
-Return<void> SurroundView2dSession::projectCameraPoints(
-        const hidl_vec<Point2dInt>& points2dCamera,
-        const hidl_string& cameraId,
-        projectCameraPoints_cb _hidl_cb) {
+Return<void> SurroundView2dSession::projectCameraPoints(const hidl_vec<Point2dInt>& points2dCamera,
+                                                        const hidl_string& cameraId,
+                                                        projectCameraPoints_cb _hidl_cb) {
     LOG(DEBUG) << __FUNCTION__;
-    scoped_lock <mutex> lock(mAccessLock);
-
+    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(INFO) << "Camera id found.";
-          break;
-      }
+        if (cameraId == evsCameraId) {
+            cameraIdFound = true;
+            LOG(DEBUG) << "Camera id found for projection: " << cameraId;
+            break;
+        }
+        cameraIndex++;
     }
 
     if (!cameraIdFound) {
-        LOG(ERROR) << "Camera id not found.";
-        _hidl_cb({});
+        LOG(ERROR) << "Camera id not found for projection: " << cameraId;
+        _hidl_cb(outPoints);
         return {};
     }
 
-    hidl_vec<Point2dFloat> outPoints;
-    outPoints.resize(points2dCamera.size());
-
     int width = mConfig.width;
     int height = mHeight;
-    for (int i=0; i<points2dCamera.size(); i++) {
-        // Assuming all the points in the image frame can be projected into 2d
-        // Surround View space. Otherwise cannot.
-        if (points2dCamera[i].x < 0 || points2dCamera[i].x > width-1 ||
-            points2dCamera[i].y < 0 || points2dCamera[i].y > height-1) {
-            LOG(WARNING) << __FUNCTION__
-                         << ": gets invalid 2d camera points. Ignored";
-            outPoints[i].isValid = false;
-            outPoints[i].x = 10000;
-            outPoints[i].y = 10000;
-        } else {
-            outPoints[i].isValid = true;
-            outPoints[i].x = 0;
-            outPoints[i].y = 0;
+    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);
@@ -414,6 +432,18 @@
 bool SurroundView2dSession::handleFrames(int sequenceId) {
     LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
 
+    // 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;
+        }
+    }
+
     if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
         LOG(DEBUG) << "Config changed. Re-allocate memory."
                    << " Old width: "
@@ -497,32 +527,27 @@
     LOG(DEBUG) << "ANativeWindowBuffer->handle: "
                << buffer->handle;
 
-    framesRecord.frames.svBuffers.resize(1);
-    SvBuffer& svBuffer = framesRecord.frames.svBuffers[0];
-    svBuffer.viewId = kSv2dViewId;
-    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_RGB_888;
-    framesRecord.frames.timestampNs = elapsedRealtimeNano();
-    framesRecord.frames.sequenceId = sequenceId;
-
     {
         scoped_lock<mutex> lock(mAccessLock);
 
-        if (framesRecord.inUse) {
-            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
-            mStream->notify(SvEvent::FRAME_DROPPED);
-        } else {
-            framesRecord.inUse = true;
-            mStream->receiveFrames(framesRecord.frames);
-        }
+        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);
+        pDesc->width = mOutputWidth;
+        pDesc->height = mOutputHeight;
+        pDesc->layers = 1;
+        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+        pDesc->stride = mSvTexture->getStride();
+        pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
+        mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
+        mFramesRecord.frames.sequenceId = sequenceId;
+
+        mFramesRecord.inUse = true;
+        mStream->receiveFrames(mFramesRecord.frames);
     }
 
     return true;
@@ -531,6 +556,11 @@
 bool SurroundView2dSession::initialize() {
     lock_guard<mutex> lock(mAccessLock, adopt_lock);
 
+    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
@@ -538,14 +568,21 @@
     mSurroundView = unique_ptr<SurroundView>(Create());
 
     SurroundViewStaticDataParams params =
-        SurroundViewStaticDataParams(GetCameras(),
-                                     Get2dParams(),
-                                     Get3dParams(),
-                                     GetUndistortionScales(),
-                                     GetBoundingBox(),
-                                     map<string, CarTexture>(),
-                                     map<string, CarPart>());
+            SurroundViewStaticDataParams(
+                    mCameraParams,
+                    mIOModuleConfig->sv2dConfig.sv2dParams,
+                    mIOModuleConfig->sv3dConfig.sv3dParams,
+                    GetUndistortionScales(),
+                    mIOModuleConfig->sv2dConfig.carBoundingBox,
+                    mIOModuleConfig->carModelConfig.carModel.texturesMap,
+                    mIOModuleConfig->carModelConfig.carModel.partsMap);
     mSurroundView->SetStaticData(params);
+    if (mSurroundView->Start2dPipeline()) {
+        LOG(INFO) << "Start2dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start2dPipeline failed";
+        return false;
+    }
 
     mInputPointers.resize(4);
     // TODO(b/157498737): the following parameters should be fed from config
@@ -561,8 +598,8 @@
     }
     LOG(INFO) << "Allocated 4 input pointers";
 
-    mOutputWidth = Get2dParams().resolution.width;
-    mOutputHeight = Get2dParams().resolution.height;
+    mOutputWidth = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.width;
+    mOutputHeight = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.height;
 
     mConfig.width = mOutputWidth;
     mConfig.blending = SvQuality::HIGH;
@@ -586,12 +623,11 @@
                                    GRALLOC_USAGE_HW_TEXTURE,
                                    "SvTexture");
 
-    //TODO(b/150412555): the 2d mapping info should be read from config file.
-    mInfo.width = 8;
-    mInfo.height = 6;
+    mInfo.width = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.width;
+    mInfo.height = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.height;
     mInfo.center.isValid = true;
-    mInfo.center.x = 0;
-    mInfo.center.y = 0;
+    mInfo.center.x = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.x;
+    mInfo.center.y = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.y;
 
     if (mSvTexture->initCheck() == OK) {
         LOG(INFO) << "Successfully allocated Graphic Buffer";
@@ -600,32 +636,22 @@
         return false;
     }
 
-    if (mSurroundView->Start2dPipeline()) {
-        LOG(INFO) << "Start2dPipeline succeeded";
-    } else {
-        LOG(ERROR) << "Start2dPipeline failed";
-        return false;
-    }
-
-    if (!setupEvs()) {
-        LOG(ERROR) << "Failed to setup EVS components for 2d session";
-        return false;
-    }
-
     mIsInitialized = true;
     return true;
 }
 
 bool SurroundView2dSession::setupEvs() {
+    // Reads the camera related information from the config object
+    const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
+
     // Setup for EVS
-    // TODO(b/157498737): We are using hard-coded camera "group0" here. It
-    // should be read from configuration file once I/O module is ready.
     LOG(INFO) << "Requesting camera list";
-    mEvs->getCameraList_1_1([this] (hidl_vec<CameraDesc> cameraList) {
+    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 == "group0") {
+            if (cam.v1.cameraId == evsGroupId) {
                 mCameraDesc = cam;
             }
         }
@@ -687,6 +713,31 @@
         LOG(INFO) << "Camera " << camId << " is opened successfully";
     }
 
+    map<string, AndroidCameraParams> cameraIdToAndroidParameters;
+    for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
+        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);
+
+    // TODO((b/156101189): the following information should be read from the
+    // I/O module.
+    for (auto& camera : mCameraParams) {
+        camera.size.width = 1920;
+        camera.size.height = 1024;
+        camera.circular_fov = 179;
+    }
+
     return true;
 }
 
@@ -709,4 +760,3 @@
 }  // namespace automotive
 }  // namespace hardware
 }  // namespace android
-
diff --git a/surround_view/service-impl/SurroundView2dSession.h b/surround_view/service-impl/SurroundView2dSession.h
index 22b7ba9..5a74c20 100644
--- a/surround_view/service-impl/SurroundView2dSession.h
+++ b/surround_view/service-impl/SurroundView2dSession.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "CoreLibSetupHelper.h"
+#include "IOModule.h"
 
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
@@ -79,7 +80,7 @@
     };
 
 public:
-    SurroundView2dSession(sp<IEvsEnumerator> pEvs);
+    SurroundView2dSession(sp<IEvsEnumerator> pEvs, IOModuleConfig* pConfig);
     ~SurroundView2dSession();
     bool initialize();
 
@@ -122,9 +123,12 @@
     // 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;
+    vector<SurroundViewCameraParams> mCameraParams;
 
     // Stream subscribed for the session.
     sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
@@ -137,7 +141,7 @@
 
     // Used to signal a set of frames is ready
     condition_variable mFramesSignal GUARDED_BY(mAccessLock);
-    bool mFramesAvailable GUARDED_BY(mAccessLock);
+    bool mProcessingEvsFrames GUARDED_BY(mAccessLock);
 
     int mSequenceId;
 
@@ -146,7 +150,7 @@
         bool inUse = false;
     };
 
-    FramesRecord framesRecord GUARDED_BY(mAccessLock);
+    FramesRecord mFramesRecord GUARDED_BY(mAccessLock);
 
     // Synchronization necessary to deconflict mCaptureThread from the main
     // service thread
diff --git a/surround_view/service-impl/SurroundView3dSession.cpp b/surround_view/service-impl/SurroundView3dSession.cpp
index a06a260..0e26ad2 100644
--- a/surround_view/service-impl/SurroundView3dSession.cpp
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -30,6 +30,7 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 
+#include "CameraUtils.h"
 #include "sv_3d_params.h"
 
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
@@ -57,6 +58,7 @@
 
 static const size_t kStreamCfgSz = sizeof(RawStreamConfig);
 static const uint8_t kGrayColor = 128;
+static const int kNumFrames = 4;
 static const int kNumChannels = 4;
 
 SurroundView3dSession::FramesHandler::FramesHandler(
@@ -69,25 +71,51 @@
     LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
     mCamera->doneWithFrame(bufDesc_1_0);
 
-    return Void();
+    return {};
 }
 
 Return<void> SurroundView3dSession::FramesHandler::deliverFrame_1_1(
     const hidl_vec<BufferDesc_1_1>& buffers) {
     LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
-    mSession->sequenceId++;
+    mSession->mSequenceId++;
 
-    // TODO(b/157498592): Use EVS frames for SV stitching.
+    {
+        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 {};
+        }
+    }
+
+    if (buffers.size() != kNumFrames) {
+        LOG(ERROR) << "The number of incoming frames is " << buffers.size()
+                   << ", which is different from the number " << kNumFrames
+                   << ", specified in config file";
+        return {};
+    }
+
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        for (int i = 0; i < kNumFrames; i++) {
+            LOG(DEBUG) << "Copying buffer No." << i
+                       << " to Surround View Service";
+            mSession->copyFromBufferToPointers(buffers[i],
+                                               mSession->mInputPointers[i]);
+        }
+    }
+
     mCamera->doneWithFrame_1_1(buffers);
 
     // Notify the session that a new set of frames is ready
     {
         scoped_lock<mutex> lock(mSession->mAccessLock);
-        mSession->mFramesAvailable = true;
+        mSession->mProcessingEvsFrames = true;
     }
     mSession->mFramesSignal.notify_all();
 
-    return Void();
+    return {};
 }
 
 Return<void> SurroundView3dSession::FramesHandler::notify(const EvsEventDesc& event) {
@@ -120,7 +148,69 @@
             break;
     }
 
-    return Void();
+    return {};
+}
+
+bool SurroundView3dSession::copyFromBufferToPointers(
+    BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
+
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
+
+    // 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;
+    }
+
+    // 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";
+    }
+
+    int stride = pDesc->stride;
+
+    // readPtr comes from EVS, and it is with 4 channels
+    uint8_t* readPtr = static_cast<uint8_t*>(inputDataPtr);
+
+    // writePtr is with 3 channels, since that is what SV core lib expects.
+    uint8_t* writePtr = static_cast<uint8_t*>(pointers.cpu_data_pointer);
+
+    for (int i = 0; i < pDesc->width; i++)
+        for (int j = 0; j < pDesc->height; j++) {
+            writePtr[(i + j * stride) * 3 + 0] =
+                readPtr[(i + j * stride) * 4 + 0];
+            writePtr[(i + j * stride) * 3 + 1] =
+                readPtr[(i + j * stride) * 4 + 1];
+            writePtr[(i + j * stride) * 3 + 2] =
+                readPtr[(i + j * stride) * 4 + 2];
+        }
+    LOG(INFO) << "Brute force copying finished";
+
+    return true;
 }
 
 void SurroundView3dSession::processFrames() {
@@ -139,17 +229,15 @@
                 break;
             }
 
-            mFramesSignal.wait(lock, [this]() {
-                return mFramesAvailable;
-            });
+            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
         }
 
-        handleFrames(sequenceId);
+        handleFrames(mSequenceId);
 
         {
             // Set the boolean to false to receive the next set of frames.
             scoped_lock<mutex> lock(mAccessLock);
-            mFramesAvailable = false;
+            mProcessingEvsFrames = false;
         }
     }
 
@@ -165,10 +253,15 @@
     }
 }
 
-SurroundView3dSession::SurroundView3dSession(sp<IEvsEnumerator> pEvs, VhalHandler* vhalHandler) :
+SurroundView3dSession::SurroundView3dSession(sp<IEvsEnumerator> pEvs,
+                                             VhalHandler* vhalHandler,
+                                             AnimationModule* animationModule,
+                                             IOModuleConfig* pConfig) :
       mEvs(pEvs),
       mStreamState(STOPPED),
-      mVhalHandler(vhalHandler) {
+      mVhalHandler(vhalHandler),
+      mAnimationModule(animationModule),
+      mIOModuleConfig(pConfig) {
     mEvsCameraIds = {"0" , "1", "2", "3"};
 }
 
@@ -215,7 +308,7 @@
     }
     mStream = stream;
 
-    sequenceId = 0;
+    mSequenceId = 0;
     startEvs();
 
     if (mVhalHandler != nullptr) {
@@ -231,6 +324,7 @@
     // 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;
@@ -268,7 +362,7 @@
     LOG(DEBUG) << __FUNCTION__;
     scoped_lock <mutex> lock(mAccessLock);
 
-    framesRecord.inUse = false;
+    mFramesRecord.inUse = false;
 
     (void)svFramesDesc;
     return {};
@@ -402,35 +496,52 @@
 }
 
 Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
-    const hidl_vec<Point2dInt>& cameraPoints,
-    const hidl_string& cameraId,
-    projectCameraPointsTo3dSurface_cb _hidl_cb) {
-
-    vector<Point3dFloat> points3d;
+        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(INFO) << "Camera id found.";
-          break;
-      }
+        if (cameraId == evsCameraId) {
+            cameraIdFound = true;
+            LOG(DEBUG) << "Camera id found for projection: " << cameraId;
+            break;
+        }
+        cameraIndex++;
     }
 
     if (!cameraIdFound) {
-        LOG(ERROR) << "Camera id not found.";
+        LOG(ERROR) << "Camera id not found for projection: " << cameraId;
         _hidl_cb(points3d);
         return {};
     }
 
     for (const auto& cameraPoint : cameraPoints) {
-        Point3dFloat point3d;
-        point3d.isValid = (cameraPoint.x >= 0
-                           && cameraPoint.x < mConfig.width
-                           && cameraPoint.y >= 0
-                           && cameraPoint.y < mConfig.height);
+        Point3dFloat point3d = {false, 0.0, 0.0, 0.0};
+
+        // Verify if camera point is within the camera resolution bounds.
+        point3d.isValid = (cameraPoint.x >= 0 && cameraPoint.x < mConfig.width &&
+                           cameraPoint.y >= 0 && cameraPoint.y < mConfig.height);
         if (!point3d.isValid) {
-            LOG(WARNING) << "Camera point out of bounds.";
+            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);
+        point3d.x = projPoint3d.x;
+        point3d.y = projPoint3d.y;
+        point3d.z = projPoint3d.z;
         points3d.push_back(point3d);
     }
     _hidl_cb(points3d);
@@ -438,9 +549,20 @@
 }
 
 bool SurroundView3dSession::handleFrames(int sequenceId) {
-
     LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
 
+    // 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;
+        }
+    }
+
     // If the width/height was changed, re-allocate the data pointer.
     if (mOutputWidth != mConfig.width
         || mOutputHeight != mConfig.height) {
@@ -505,6 +627,19 @@
         LOG(WARNING) << "VhalHandler is null. Ignored";
     }
 
+    vector<AnimationParam> params;
+    if (mAnimationModule != nullptr) {
+        params = mAnimationModule->getUpdatedAnimationParams(mPropertyValues);
+    } else {
+        LOG(WARNING) << "AnimationModule is null. Ignored";
+    }
+
+    if (!params.empty()) {
+        mSurroundView->SetAnimations(params);
+    } else {
+        LOG(INFO) << "AnimationParams is empty. Ignored";
+    }
+
     if (mSurroundView->Get3dSurroundView(
         mInputPointers, matrix, &mOutputPointer)) {
         LOG(INFO) << "Get3dSurroundView succeeded";
@@ -547,32 +682,27 @@
     ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
     LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
 
-    framesRecord.frames.svBuffers.resize(1);
-    SvBuffer& svBuffer = framesRecord.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;
-    framesRecord.frames.timestampNs = elapsedRealtimeNano();
-    framesRecord.frames.sequenceId = sequenceId;
-
     {
         scoped_lock<mutex> lock(mAccessLock);
 
-        if (framesRecord.inUse) {
-            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
-            mStream->notify(SvEvent::FRAME_DROPPED);
-        } else {
-            framesRecord.inUse = true;
-            mStream->receiveFrames(framesRecord.frames);
-        }
+        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);
     }
 
     return true;
@@ -581,6 +711,11 @@
 bool SurroundView3dSession::initialize() {
     lock_guard<mutex> lock(mAccessLock, adopt_lock);
 
+    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
@@ -588,31 +723,32 @@
     mSurroundView = unique_ptr<SurroundView>(Create());
 
     SurroundViewStaticDataParams params =
-        SurroundViewStaticDataParams(GetCameras(),
-                                     Get2dParams(),
-                                     Get3dParams(),
-                                     GetUndistortionScales(),
-                                     GetBoundingBox(),
-                                     map<string, CarTexture>(),
-                                     map<string, CarPart>());
+            SurroundViewStaticDataParams(
+                    mCameraParams,
+                    mIOModuleConfig->sv2dConfig.sv2dParams,
+                    mIOModuleConfig->sv3dConfig.sv3dParams,
+                    GetUndistortionScales(),
+                    mIOModuleConfig->sv2dConfig.carBoundingBox,
+                    mIOModuleConfig->carModelConfig.carModel.texturesMap,
+                    mIOModuleConfig->carModelConfig.carModel.partsMap);
     mSurroundView->SetStaticData(params);
 
-    // TODO(b/150412555): remove after EVS camera is used
-    mInputPointers = mSurroundView->ReadImages(
-        "/etc/automotive/sv/cam0.png",
-        "/etc/automotive/sv/cam1.png",
-        "/etc/automotive/sv/cam2.png",
-        "/etc/automotive/sv/cam3.png");
-    if (mInputPointers.size() == 4
-        && mInputPointers[0].cpu_data_pointer != nullptr) {
-        LOG(INFO) << "ReadImages succeeded";
-    } else {
-        LOG(ERROR) << "Failed to read images";
-        return false;
+    mInputPointers.resize(4);
+    // TODO(b/157498737): the following parameters should be fed from config
+    // files. Remove the hard-coding values once I/O module is ready.
+    for (int i = 0; i < 4; i++) {
+        mInputPointers[i].width = 1920;
+        mInputPointers[i].height = 1024;
+        mInputPointers[i].format = Format::RGB;
+        mInputPointers[i].cpu_data_pointer =
+                (void*)new uint8_t[mInputPointers[i].width *
+                                   mInputPointers[i].height *
+                                   kNumChannels];
     }
+    LOG(INFO) << "Allocated 4 input pointers";
 
-    mOutputWidth = Get3dParams().resolution.width;
-    mOutputHeight = Get3dParams().resolution.height;
+    mOutputWidth = mIOModuleConfig->sv3dConfig.sv3dParams.resolution.width;
+    mOutputHeight = mIOModuleConfig->sv3dConfig.sv3dParams.resolution.height;
 
     mConfig.width = mOutputWidth;
     mConfig.height = mOutputHeight;
@@ -643,25 +779,23 @@
         return false;
     }
 
-    if (!setupEvs()) {
-        LOG(ERROR) << "Failed to setup EVS components for 3d session";
-        return false;
-    }
 
     mIsInitialized = true;
     return true;
 }
 
 bool SurroundView3dSession::setupEvs() {
+    // Reads the camera related information from the config object
+    const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
+
     // Setup for EVS
-    // TODO(b/157498737): We are using hard-coded camera "group0" here. It
-    // should be read from configuration file once I/O module is ready.
     LOG(INFO) << "Requesting camera list";
-    mEvs->getCameraList_1_1([this] (hidl_vec<CameraDesc> cameraList) {
+    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 == "group0") {
+            if (cam.v1.cameraId == evsGroupId) {
                 mCameraDesc = cam;
             }
         }
@@ -723,6 +857,31 @@
         LOG(INFO) << "Camera " << camId << " is opened successfully";
     }
 
+    map<string, AndroidCameraParams> cameraIdToAndroidParameters;
+    for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
+        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);
+
+    // TODO((b/156101189): the following information should be read from the
+    // I/O module.
+    for (auto& camera : mCameraParams) {
+        camera.size.width = 1920;
+        camera.size.height = 1024;
+        camera.circular_fov = 179;
+    }
+
     return true;
 }
 
@@ -745,4 +904,3 @@
 }  // namespace automotive
 }  // namespace hardware
 }  // namespace android
-
diff --git a/surround_view/service-impl/SurroundView3dSession.h b/surround_view/service-impl/SurroundView3dSession.h
index fbb974f..09f4c90 100644
--- a/surround_view/service-impl/SurroundView3dSession.h
+++ b/surround_view/service-impl/SurroundView3dSession.h
@@ -26,6 +26,7 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include "AnimationModule.h"
 #include "CoreLibSetupHelper.h"
 #include "VhalHandler.h"
 
@@ -82,7 +83,10 @@
 
 public:
     // TODO(b/158479099): use strong pointer for VhalHandler
-    SurroundView3dSession(sp<IEvsEnumerator> pEvs, VhalHandler* vhalHandler);
+    SurroundView3dSession(sp<IEvsEnumerator> pEvs,
+                          VhalHandler* vhalHandler,
+                          AnimationModule* animationModule,
+                          IOModuleConfig* pConfig);
     ~SurroundView3dSession();
     bool initialize();
 
@@ -113,6 +117,9 @@
 
     bool handleFrames(int sequenceId);
 
+    bool copyFromBufferToPointers(BufferDesc_1_1 buffer,
+                                  SurroundViewInputBufferPointers pointers);
+
     enum StreamStateValues {
         STOPPED,
         RUNNING,
@@ -126,6 +133,7 @@
     // Instance and metadata for the opened Evs Camera
     sp<IEvsCamera> mCamera;
     CameraDesc mCameraDesc;
+    vector<SurroundViewCameraParams> mCameraParams;
 
     // Stream subscribed for the session.
     sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
@@ -138,16 +146,16 @@
 
     // Used to signal a set of frames is ready
     condition_variable mFramesSignal GUARDED_BY(mAccessLock);
-    bool mFramesAvailable GUARDED_BY(mAccessLock);
+    bool mProcessingEvsFrames GUARDED_BY(mAccessLock);
 
-    int sequenceId;
+    int mSequenceId;
 
     struct FramesRecord {
         SvFramesDesc frames;
         bool inUse = false;
     };
 
-    FramesRecord framesRecord GUARDED_BY(mAccessLock);
+    FramesRecord mFramesRecord GUARDED_BY(mAccessLock);
 
     // Synchronization necessary to deconflict mCaptureThread from the main service thread
     mutex mAccessLock;
@@ -170,6 +178,8 @@
     bool mIsInitialized GUARDED_BY(mAccessLock) = false;
 
     VhalHandler* mVhalHandler;
+    AnimationModule* mAnimationModule;
+    IOModuleConfig* mIOModuleConfig;
 
     std::vector<VehiclePropValue> mPropertyValues;
 };
diff --git a/surround_view/service-impl/SurroundViewService.cpp b/surround_view/service-impl/SurroundViewService.cpp
index a1c97bd..1e8446e 100644
--- a/surround_view/service-impl/SurroundViewService.cpp
+++ b/surround_view/service-impl/SurroundViewService.cpp
@@ -39,10 +39,12 @@
 
 SurroundViewService::SurroundViewService() {
     mVhalHandler = new VhalHandler();
+    mIOModule = new IOModule("/etc/automotive/sv/sv_sample_config.xml");
 }
 
 SurroundViewService::~SurroundViewService() {
     delete mVhalHandler;
+    delete mAnimationModule;
 }
 
 sp<SurroundViewService> SurroundViewService::getInstance() {
@@ -67,6 +69,27 @@
         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;
+    }
+
+    // TODO(haoxiangl): check whether 2d/3d/animation is available or not.
+
+    // 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.
@@ -94,7 +117,7 @@
         LOG(WARNING) << "Only one 2d session is supported at the same time";
         _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
     } else {
-        sSurroundView2dSession = new SurroundView2dSession(mEvs);
+        sSurroundView2dSession = new SurroundView2dSession(mEvs, &mConfig);
         if (sSurroundView2dSession->initialize()) {
             _hidl_cb(sSurroundView2dSession, SvResult::OK);
         } else {
@@ -126,7 +149,10 @@
         LOG(WARNING) << "Only one 3d session is supported at the same time";
         _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
     } else {
-        sSurroundView3dSession = new SurroundView3dSession(mEvs, mVhalHandler);
+        sSurroundView3dSession = new SurroundView3dSession(mEvs,
+                                                           mVhalHandler,
+                                                           mAnimationModule,
+                                                           &mConfig);
         if (sSurroundView3dSession->initialize()) {
             _hidl_cb(sSurroundView3dSession, SvResult::OK);
         } else {
diff --git a/surround_view/service-impl/SurroundViewService.h b/surround_view/service-impl/SurroundViewService.h
index edff4df..6950a27 100644
--- a/surround_view/service-impl/SurroundViewService.h
+++ b/surround_view/service-impl/SurroundViewService.h
@@ -18,6 +18,8 @@
 
 #include "SurroundView2dSession.h"
 #include "SurroundView3dSession.h"
+#include "AnimationModule.h"
+#include "IOModule.h"
 #include "VhalHandler.h"
 
 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
@@ -61,6 +63,9 @@
     ~SurroundViewService();
 
     VhalHandler* mVhalHandler;
+    AnimationModule* mAnimationModule;
+    IOModule* mIOModule;
+    IOModuleConfig mConfig;
 
     bool initialize();
     sp<IEvsEnumerator> mEvs;
diff --git a/surround_view/service-impl/VhalHandler.cpp b/surround_view/service-impl/VhalHandler.cpp
index f1294d9..4b9ac23 100644
--- a/surround_view/service-impl/VhalHandler.cpp
+++ b/surround_view/service-impl/VhalHandler.cpp
@@ -96,18 +96,21 @@
         // Write to back property values, note lock is not needed as only this thread uses it.
         std::vector<VehiclePropValue> vehiclePropValuesUpdated;
         for (auto& propertyToRead : propertiesToRead) {
-            // VehiclePropValue vehiclePropValue;
+            StatusCode statusResult;
+            VehiclePropValue propValueResult;
             mVhalServicePtr->get(propertyToRead,
-                                 [&vehiclePropValuesUpdated](StatusCode status,
-                                                             const VehiclePropValue& propValue) {
-                                     if (status != StatusCode::OK) {
-                                         LOG(ERROR) << "Failed to read vhal property: "
-                                                    << propValue.prop << ", with status code: "
-                                                    << static_cast<int32_t>(status);
-                                     } else {
-                                         vehiclePropValuesUpdated.push_back(propValue);
-                                     }
+                                 [&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.
@@ -172,6 +175,19 @@
     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);
diff --git a/surround_view/service-impl/VhalHandler.h b/surround_view/service-impl/VhalHandler.h
index 23941f0..029e414 100644
--- a/surround_view/service-impl/VhalHandler.h
+++ b/surround_view/service-impl/VhalHandler.h
@@ -60,6 +60,10 @@
     // 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();
 
diff --git a/surround_view/service-impl/VhalHandlerTests.cpp b/surround_view/service-impl/VhalHandlerTests.cpp
index 2d0ef40..cd7c0e3 100644
--- a/surround_view/service-impl/VhalHandlerTests.cpp
+++ b/surround_view/service-impl/VhalHandlerTests.cpp
@@ -30,12 +30,23 @@
 namespace implementation {
 namespace {
 
+using vehicle::V2_0::VehicleArea;
+using vehicle::V2_0::VehicleProperty;
+
 void SetSamplePropertiesToRead(VhalHandler* vhalHandler) {
-    std::vector<vehicle::V2_0::VehiclePropValue> properties_to_read;
-    vehicle::V2_0::VehiclePropValue property_read;
-    property_read.prop = static_cast<int32_t>(vehicle::V2_0::VehicleProperty::INFO_MODEL);
-    properties_to_read.push_back(property_read);
-    ASSERT_TRUE(vhalHandler->setPropertiesToRead(properties_to_read));
+    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) {
@@ -85,9 +96,24 @@
 
     ASSERT_TRUE(vhalHandler.startPropertiesUpdate());
     sleep(1);
-    std::vector<vehicle::V2_0::VehiclePropValue> property_values;
-    EXPECT_TRUE(vhalHandler.getPropertyValues(&property_values));
-    EXPECT_EQ(property_values.size(), 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());
 }
diff --git a/surround_view/service-impl/core_lib.h b/surround_view/service-impl/core_lib.h
index c2d31af..7a9e67d 100644
--- a/surround_view/service-impl/core_lib.h
+++ b/surround_view/service-impl/core_lib.h
@@ -1,3 +1,19 @@
+/*
+ * 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_
 
@@ -16,60 +32,57 @@
 // 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;
+    // (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;
+    // (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() : 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(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) {}
+    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; }
+    // 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;
-  }
+    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;
-  }
+    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;
+    // x coordinate.
+    T x;
 
-  // y coordinate.
-  T y;
+    // y coordinate.
+    T y;
 
-  Coordinate2dBase() : x(0), y(0) {}
+    Coordinate2dBase() : x(0), y(0) {}
 
-  Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
+    Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
 
-  bool operator==(const Coordinate2dBase& rhs) const {
-    return x == rhs.x && y == rhs.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;
-  }
+    Coordinate2dBase& operator=(const Coordinate2dBase& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        return *this;
+    }
 };
 
 // integer type size.
@@ -79,82 +92,80 @@
 typedef Coordinate2dBase<float> Coordinate2dFloat;
 
 struct Coordinate3dFloat {
-  // x coordinate.
-  float x;
+    // x coordinate.
+    float x;
 
-  // y coordinate.
-  float y;
+    // y coordinate.
+    float y;
 
-  // z coordinate.
-  float z;
+    // z coordinate.
+    float z;
 
-  Coordinate3dFloat() : x(0), y(0), z(0) {}
+    Coordinate3dFloat() : x(0), y(0), z(0) {}
 
-  Coordinate3dFloat(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
+    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;
-  }
+    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;
-  }
+    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;
+    // 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 coordinate y in vertical direction.
+    float y;
 
-  // pixel weight, range in [0, 1].
-  float weight;
+    // pixel weight, range in [0, 1].
+    float weight;
 
-  PixelWeight() : x(-1), y(-1), weight(0) {}
+    PixelWeight() : x(-1), y(-1), weight(0) {}
 
-  PixelWeight(int x_, int y_, int weight_) : x(x_), y(y_), weight(weight_) {}
+    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;
-  }
+    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;
-  }
+    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;
+    // width of size.
+    T width;
 
-  // height of size.
-  T height;
+    // height of size.
+    T height;
 
-  Size2dBase() : width(0), height(0) {}
+    Size2dBase() : width(0), height(0) {}
 
-  Size2dBase(T width_, T height_) : width(width_), height(height_) {}
+    Size2dBase(T width_, T height_) : width(width_), height(height_) {}
 
-  bool IsValid() const { return width > 0 && height > 0; }
+    bool IsValid() const { return width > 0 && height > 0; }
 
-  bool operator==(const Size2dBase& rhs) const {
-    return width == rhs.width && height == rhs.height;
-  }
+    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;
-  }
+    Size2dBase& operator=(const Size2dBase& rhs) {
+        width = rhs.width;
+        height = rhs.height;
+        return *this;
+    }
 };
 
 // integer type size.
@@ -165,314 +176,338 @@
 
 //  surround view 2d parameters
 struct SurroundView2dParams {
-  // surround view 2d image resolution (width, height).
-  Size2dInteger resolution;
+    // 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 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;
+    // the center of surround view 2d area in surround view coordinate
+    // (consistent with extrinsics coordinate).
+    Coordinate2dFloat physical_center;
 
-  SurroundView2dParams()
-      : resolution{0, 0},
-        physical_size{0.0f, 0.0f},
-        physical_center{0.0f, 0.0f} {}
+    // Enumeration for list of 2d blending types.
+    enum BlendingType { MULTIBAND = 0, ALPHA };
 
-  SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
-                       Coordinate2dFloat physical_center_)
-      : resolution(resolution_),
-        physical_size(physical_size_),
-        physical_center(physical_center_) {}
+    // Blending type for high quality preset.
+    BlendingType high_quality_blending;
 
-  // Checks if data is valid.
-  bool IsValid() const {
-    return resolution.IsValid() && physical_size.IsValid();
-  }
+    // Blending type for low quality preset.
+    BlendingType low_quality_blending;
 
-  bool operator==(const SurroundView2dParams& rhs) const {
-    return resolution == rhs.resolution && physical_size == rhs.physical_size &&
-           physical_center == rhs.physical_center;
-  }
+    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) {}
 
-  SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
-    resolution = rhs.resolution;
-    physical_size = rhs.physical_size;
-    physical_center = rhs.physical_center;
-    return *this;
-  }
+    SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
+                         Coordinate2dFloat physical_center_) :
+          resolution(resolution_),
+          physical_size(physical_size_),
+          physical_center(physical_center_),
+          high_quality_blending(BlendingType::MULTIBAND),
+          low_quality_blending(BlendingType::ALPHA) {}
+
+    // 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;
+    }
+
+    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;
+        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.
+    // 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;
+    // 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;
+    // 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;
+    // 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 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 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;
+    // 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;
+    // render output image size.
+    Size2dInteger resolution;
 
-  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) {}
+    // Include shadows in high details preset.
+    bool high_details_shadows;
 
-  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_) {}
+    // Include reflections in high details preset.
+    bool high_details_reflections;
 
-  // 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();
-  }
+    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) {}
 
-  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;
-  }
+    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) {}
 
-  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;
-    return *this;
-  }
+    // 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];
+    // 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];
+    // lens distortion parameters.
+    float distorion[4];
 
-  // rotation vector.
-  float rvec[3];
+    // rotation vector.
+    float rvec[3];
 
-  // translation vector.
-  float tvec[3];
+    // translation vector.
+    float tvec[3];
 
-  // camera image size (width, height).
-  Size2dInteger size;
+    // camera image size (width, height).
+    Size2dInteger size;
 
-  // fisheye circular fov.
-  float circular_fov;
+    // fisheye circular fov.
+    float circular_fov;
 
-  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;
-  }
+    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;
-  }
+    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];
+    // 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)));
-  }
+    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;
-  }
+    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;
+    // Uniqiue Id identifying each overlay.
+    uint16_t id;
 
-  // List of overlay vertices. 3 consecutive vertices form a triangle.
-  std::vector<OverlayVertex> vertices;
+    // 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_;
-  }
+    // 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>();
-  }
+    // 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;
+    // 3d position in (x, y, z).
+    std::array<float, 3> pos;
 
-  // unit normal at vertex, used for diffuse shading.
-  std::array<float, 3> normal;
+    // 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;
+    // 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};
-  }
+    // 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) {}
+    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 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
+    // 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;
+    // 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;
-  }
+    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;
+    // 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]
+    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;
+    // 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;
+    // 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.
-  }
+    // 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;
+    // 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.
@@ -482,318 +517,304 @@
 // 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;
+    // Car part vertices.
+    std::vector<CarVertex> vertices;
 
-  // Properties/attributes describing car material.
-  CarMaterial material;
+    // 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;
+    // 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;
+    // 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;
+    // 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(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;
-  }
+    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;
+    // part id
+    std::string part_id;
 
-  // model matrix.
-  Mat4x4 model_matrix;
+    // model matrix.
+    Mat4x4 model_matrix;
 
-  // bool flag indicating if the model matrix is updated from last
-  // SetAnimations() call.
-  bool is_model_update;
+    // bool flag indicating if the model matrix is updated from last
+    // SetAnimations() call.
+    bool is_model_update;
 
-  // gamma.
-  float gamma;
+    // gamma.
+    float gamma;
 
-  // bool flag indicating if gamma is updated from last
-  // SetAnimations() call.
-  bool is_gamma_update;
+    // bool flag indicating if gamma is updated from last
+    // SetAnimations() call.
+    bool is_gamma_update;
 
-  // texture id.
-  std::string texture_id;
+    // texture id.
+    std::string texture_id;
 
-  // bool flag indicating if texture is updated from last
-  // SetAnimations() call.
-  bool is_texture_update;
+    // 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;
-  }
+    // 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) {}
+    // 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 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 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;
-  }
+    void SetTexture(const std::string& tex_id) {
+        is_texture_update = true;
+        texture_id = tex_id;
+    }
 };
 
 enum Format {
-  GRAY = 0,
-  RGB = 1,
-  RGBA = 2,
+    GRAY = 0,
+    RGB = 1,
+    RGBA = 2,
 };
 
 // collection of surround view static data params.
 struct SurroundViewStaticDataParams {
-  std::vector<SurroundViewCameraParams> cameras_params;
+    std::vector<SurroundViewCameraParams> cameras_params;
 
-  // surround view 2d parameters.
-  SurroundView2dParams surround_view_2d_params;
+    // surround view 2d parameters.
+    SurroundView2dParams surround_view_2d_params;
 
-  // surround view 3d parameters.
-  SurroundView3dParams surround_view_3d_params;
+    // surround view 3d parameters.
+    SurroundView3dParams surround_view_3d_params;
 
-  // undistortion focal length scales.
-  std::vector<float> undistortion_focal_length_scales;
+    // undistortion focal length scales.
+    std::vector<float> undistortion_focal_length_scales;
 
-  // car model bounding box for 2d surround view.
-  BoundingBox car_model_bb;
+    // 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 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;
+    // 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) {}
+    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) {}
 };
 
 struct SurroundViewInputBufferPointers {
-  void* gpu_data_pointer;
-  void* cpu_data_pointer;
-  Format format;
-  int width;
-  int height;
-  SurroundViewInputBufferPointers()
-      : gpu_data_pointer(nullptr),
-        cpu_data_pointer(nullptr),
-        width(0),
-        height(0) {}
-  SurroundViewInputBufferPointers(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_) {}
+    void* gpu_data_pointer;
+    void* cpu_data_pointer;
+    Format format;
+    int width;
+    int height;
+    SurroundViewInputBufferPointers() :
+          gpu_data_pointer(nullptr), cpu_data_pointer(nullptr), width(0), height(0) {}
+    SurroundViewInputBufferPointers(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_) {}
 };
 
 struct SurroundViewResultPointer {
-  void* data_pointer;
-  Format format;
-  int width;
-  int height;
-  bool is_data_preallocated;
-  SurroundViewResultPointer()
-      : data_pointer(nullptr),
-        width(0),
-        height(0),
-        is_data_preallocated(false) {}
+    void* data_pointer;
+    Format format;
+    int width;
+    int height;
+    bool is_data_preallocated;
+    SurroundViewResultPointer() :
+          data_pointer(nullptr), width(0), height(0), is_data_preallocated(false) {}
 
-  // Constructor with result 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;
-    data_pointer =
-        static_cast<void*>(new char[width * height * byte_per_pixel]);
-    is_data_preallocated = false;
-  }
-
-  // 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* data_pointer_, Format format_, int width_,
-                            int height_)
-      : data_pointer(data_pointer_),
-        format(format_),
-        width(width_),
-        height(height_),
-        is_data_preallocated(true) {}
-
-  ~SurroundViewResultPointer() {
-    if (data_pointer) {
-      // TODO(b/154365307): Fix freeing up of pre-allocated memory.
-      // if (!is_data_preallocated) {
-      //   delete[] static_cast<char*>(data_pointer);
-      // }
-      data_pointer = nullptr;
+    // Constructor with result 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;
+        data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
+        is_data_preallocated = false;
     }
-  }
+
+    // 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* data_pointer_, Format format_, int width_, int height_) :
+          data_pointer(data_pointer_),
+          format(format_),
+          width(width_),
+          height(height_),
+          is_data_preallocated(true) {}
+
+    ~SurroundViewResultPointer() {
+        if (data_pointer) {
+            // TODO(b/154365307): Fix freeing up of pre-allocated memory.
+            // if (!is_data_preallocated) {
+            //   delete[] static_cast<char*>(data_pointer);
+            // }
+            data_pointer = nullptr;
+        }
+    }
 };
 
 class SurroundView {
- public:
-  virtual ~SurroundView() = default;
+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;
+    // 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 2d pipeline. Returns false if error occurs.
+    virtual bool Start2dPipeline() = 0;
 
-  // Starts 3d pipeline. Returns false if error occurs.
-  virtual bool Start3dPipeline() = 0;
+    // Starts 3d pipeline. Returns false if error occurs.
+    virtual bool Start3dPipeline() = 0;
 
-  // Stops 2d pipleline. It releases resource owned by the pipeline.
-  // Returns false if error occurs.
-  virtual void Stop2dPipeline() = 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;
+    // 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 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;
+    // 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 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;
+    // 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 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.
+    // 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;
+    // 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;
 
-  // Sets 3d overlays.
-  virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 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;
+    // 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.
-  // TODO(xxqian): remove thest two fns.
-  virtual std::vector<SurroundViewInputBufferPointers> ReadImages(
-      const char* filename0, const char* filename1, const char* filename2,
-      const char* filename3) = 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;
+    virtual void WriteImage(const SurroundViewResultPointer result_pointerer,
+                            const char* filename) = 0;
 };
 
 SurroundView* Create();
diff --git a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
index 3988762..5ca36a5 100755
--- a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
index e9f94db..7f2e039 100755
--- a/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/x86-64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86/libcore_lib_shared.so b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
index b82d025..9d0f4ef 100755
--- a/surround_view/service-impl/lib/x86/libcore_lib_shared.so
+++ b/surround_view/service-impl/lib/x86/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/test_data/cube.mtl b/surround_view/service-impl/test_data/cube.mtl
deleted file mode 100644
index 2f4e865..0000000
--- a/surround_view/service-impl/test_data/cube.mtl
+++ /dev/null
@@ -1,5 +0,0 @@
-newmtl flatwhite
-d 1.0000
-illum 1
-Ka 0.5000 0.5000 0.5000
-Kd 1.0000 1.0000 1.0000
diff --git a/surround_view/service-impl/test_data/cube.obj b/surround_view/service-impl/test_data/cube.obj
deleted file mode 100644
index 60ae1b2..0000000
--- a/surround_view/service-impl/test_data/cube.obj
+++ /dev/null
@@ -1,32 +0,0 @@
-mtllib cube.mtl
-g cube
- 
-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
-usemtl flatwhite 
-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/surround_view/service-impl/test_data/sample_car.obj b/surround_view/service-impl/test_data/sample_car.obj
new file mode 100644
index 0000000..3600a7b
--- /dev/null
+++ b/surround_view/service-impl/test_data/sample_car.obj
@@ -0,0 +1,64 @@
+# 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/surround_view/service-impl/test_data/sample_car_material.mtl b/surround_view/service-impl/test_data/sample_car_material.mtl
new file mode 100644
index 0000000..346d5bd
--- /dev/null
+++ b/surround_view/service-impl/test_data/sample_car_material.mtl
@@ -0,0 +1,14 @@
+# 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
+
+newmtl window
+    d 1.0000
+    illum 1
+    Ka 0.5000 0.5000 0.5000
+    Kd 1.0000 0.0000 0.0000
diff --git a/surround_view/service-impl/test_data/sv_sample_car_model_config.xml b/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
new file mode 100644
index 0000000..60541a8
--- /dev/null
+++ b/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
@@ -0,0 +1,79 @@
+<?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/surround_view/service-impl/test_data/sv_sample_config.xml b/surround_view/service-impl/test_data/sv_sample_config.xml
new file mode 100644
index 0000000..484e2fd
--- /dev/null
+++ b/surround_view/service-impl/test_data/sv_sample_config.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SurroundViewConfig>
+    <Version>1.0</Version>
+
+    <CameraConfig>
+        <EvsGroupId>v4l2loopback_group0</EvsGroupId>
+        <EvsCameraIds>
+            <Front>/dev/video90</Front>
+            <Right>/dev/video91</Right>
+            <Rear>/dev/video92</Rear>
+            <Left>/dev/video93</Left>
+        </EvsCameraIds>
+        <Masks>
+            <Front>/vendor/mask_front.png</Front>
+            <Right>/vendor/mask_right.png</Right>
+            <Rear>/vendor/mask_rear.png</Rear>
+            <Left>/vendor/mask_left.png</Left>
+        </Masks>
+    </CameraConfig>
+
+    <Sv2dEnabled>true</Sv2dEnabled>
+    <Sv2dParams>
+        <OutputResolution>
+            <Width>600</Width>
+            <Height>900</Height>
+        </OutputResolution>
+        <GroundMapping>
+            <Width>6.0</Width>
+            <Height>9.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>
+    </Sv2dParams>
+
+    <Sv3dEnabled>true</Sv3dEnabled>
+    <Sv3dAnimationsEnabled>true</Sv3dAnimationsEnabled>
+    <CarModelConfigFile>/etc/automotive/sv/sv_sample_car_model_config.xml</CarModelConfigFile>
+    <CarModelObjFile>/etc/automotive/sv/sample_car.obj</CarModelObjFile>
+    <Sv3dParams>
+        <OutputResolution>
+            <Width>1920</Width>
+            <Height>1080</Height>
+        </OutputResolution>
+        <BowlParams>
+            <PlaneRadius>6.0</PlaneRadius>
+            <PlaneDivisions>20</PlaneDivisions>
+            <CurveHeight>5.0</CurveHeight>
+            <CurveDivisions>30</CurveDivisions>
+            <AngularDivisions>50</AngularDivisions>
+            <CurveCoefficient>2.0</CurveCoefficient>
+        </BowlParams>
+        <HighQualityDetails>
+            <Shadows>true</Shadows>
+            <Reflections>true</Reflections>
+        </HighQualityDetails>
+    </Sv3dParams>
+</SurroundViewConfig>
diff --git a/tests/CarDeveloperOptions/res/values-am/strings.xml b/tests/CarDeveloperOptions/res/values-am/strings.xml
index 051b9cc..ba77bc5 100644
--- a/tests/CarDeveloperOptions/res/values-am/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-am/strings.xml
@@ -3083,7 +3083,7 @@
     <string name="keywords_location" msgid="6439463166207072559">"አቅራቢያ፣ አካባቢ፣ ታሪክ፣ ሪፖርት ማድረግ"</string>
     <string name="keywords_accounts" msgid="5908945725229306088">"መለያ"</string>
     <string name="keywords_users" msgid="5880705776023155640">"ገደብ፣ ገድብ፣ የተገደበ"</string>
-    <string name="keywords_keyboard_and_ime" msgid="3327265741354129990">"የጽሑፍ እርማት፣ ትክክል፣ ድምፅ፣ ንዘር፣ ራስ-ሰር፣ ቋንቋ፣ የጣት ምልክት፣ ጠቁም፣ የአስተያየት ጥቆማ፣ ገጽታ፣ የሚያስከፋ፣ ቃል፣ ተይብ፣ ስሜት ገላጭ ምስል፣ አለምአቀፍ"</string>
+    <string name="keywords_keyboard_and_ime" msgid="3327265741354129990">"የጽሑፍ እርማት፣ ትክክል፣ ድምፅ፣ ንዘር፣ ራስ-ሰር፣ ቋንቋ፣ የጣት ምልክት፣ ጠቁም፣ የአስተያየት ጥቆማ፣ ገጽታ፣ የሚያስከፋ፣ ቃል፣ ተይብ፣ ስሜት ገላጭ ምስል፣ ዓለምአቀፍ"</string>
     <string name="keywords_reset_apps" msgid="2645701455052020435">"ዳግም አስጀምር፣ ምርጫዎች፣ ነባሪ"</string>
     <string name="keywords_all_apps" msgid="846444448435698930">"መተግበሪያዎች፣ ውርድ፣ መተግበሪያዎች፣ ስርዓት"</string>
     <string name="keywords_app_permissions" msgid="8539841019997048500">"መተግበሪያዎች፣ ፈቃዶች፣ ደህንነት"</string>
@@ -4358,7 +4358,7 @@
     <string name="preferred_network_mode_lte_summary" msgid="4281029367896990461">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE"</string>
     <string name="preferred_network_mode_lte_gsm_wcdma_summary" msgid="149627151786465701">"ተመራጭ የአውታረ መረብ ሁነታ፦ GSM/WCDMA/LTE"</string>
     <string name="preferred_network_mode_lte_cdma_evdo_summary" msgid="2892417308574212352">"ተመራጭ የአውታረ መረብ ሁነታ፦ CDMA+LTE/EVDO"</string>
-    <string name="preferred_network_mode_global_summary" msgid="487001671043476488">"ተመራጭ የአውታረ መረብ ሁነታ፦ አለምአቀፍ"</string>
+    <string name="preferred_network_mode_global_summary" msgid="487001671043476488">"ተመራጭ የአውታረ መረብ ሁነታ፦ ዓለምአቀፍ"</string>
     <string name="preferred_network_mode_lte_wcdma_summary" msgid="9029884385644299102">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE / WCDMA"</string>
     <string name="preferred_network_mode_lte_gsm_umts_summary" msgid="6583001637967763033">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE / GSM / UMTS"</string>
     <string name="preferred_network_mode_lte_cdma_summary" msgid="344294371859765484">"ተመራጭ የአውታረ መረብ ሁነታ፦ LTE / CDMA"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ar/strings.xml b/tests/CarDeveloperOptions/res/values-ar/strings.xml
index 24b1773..70e1e1c 100644
--- a/tests/CarDeveloperOptions/res/values-ar/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/strings.xml
@@ -1799,7 +1799,7 @@
     <string name="lockpassword_confirm_passwords_dont_match" msgid="1783767008133345784">"كلمات المرور غير متطابقة"</string>
     <string name="lockpassword_confirm_pins_dont_match" msgid="5444357293637748942">"أرقام التعريف الشخصي غير متطابقة"</string>
     <string name="lockpassword_draw_your_pattern_again_header" msgid="9017394036814402348">"ارسم النقش مرة أخرى"</string>
-    <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"تحديد طريقة فتح القفل"</string>
+    <string name="lockpassword_choose_lock_generic_header" msgid="4418423132980560119">"اختيار طريقة فتح القفل"</string>
     <string name="lockpassword_password_set_toast" msgid="601928982984489868">"تم تعيين كلمة المرور"</string>
     <string name="lockpassword_pin_set_toast" msgid="172594825722240059">"تم تعيين رمز PIN"</string>
     <string name="lockpassword_pattern_set_toast" msgid="6923260369475481406">"تم تعيين النقش"</string>
diff --git a/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml b/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
index 4c69e86..9e025f3 100644
--- a/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-b+sr+Latn/strings.xml
@@ -3491,7 +3491,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Dodajte vremenski raspored"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Izbriši raspored"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Odaberite tip rasporeda"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Želite li da izbrišete pravilo „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Želite da izbrišete pravilo „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Izbriši"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Nepoznato"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Ova podešavanja trenutno ne mogu da se menjaju. Aplikacija (<xliff:g id="APP_NAME">%1$s</xliff:g>) je automatski uključila režim Ne uznemiravaj sa prilagođenim ponašanjem."</string>
diff --git a/tests/CarDeveloperOptions/res/values-de/strings.xml b/tests/CarDeveloperOptions/res/values-de/strings.xml
index 022e8c8..c533d17 100644
--- a/tests/CarDeveloperOptions/res/values-de/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-de/strings.xml
@@ -3471,7 +3471,7 @@
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Täglich"</string>
     <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Wecker kann Schlusszeit außer Kraft setzen"</string>
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Zeitplan wird deaktiviert, wenn ein Wecker klingelt"</string>
-    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\"Bitte nicht stören\"-Verhalten"</string>
+    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\"Bitte nicht stören\"-Modus"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Standardeinstellungen verwenden"</string>
     <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Benutzerdefinierte Einstellungen festlegen"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"Für \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
diff --git a/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml b/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
index 424e042..54d857e 100644
--- a/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es-rUS/strings.xml
@@ -3440,7 +3440,7 @@
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"Agregar programa de eventos"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Agregar programa de tiempo"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Borrar programa"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Elegir tipo de programa"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Elegir el tipo de programa"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"¿Quieres borrar la regla \"<xliff:g id="RULE">%1$s</xliff:g>\"?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Borrar"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Desconocido"</string>
diff --git a/tests/CarDeveloperOptions/res/values-es/strings.xml b/tests/CarDeveloperOptions/res/values-es/strings.xml
index a7a06e2..7374f0d 100644
--- a/tests/CarDeveloperOptions/res/values-es/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es/strings.xml
@@ -3443,7 +3443,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Añadir programación horaria"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Eliminar programación"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Elige un tipo de programación"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"¿Quieres eliminar la regla \"<xliff:g id="RULE">%1$s</xliff:g>\"?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"¿Eliminar regla \"<xliff:g id="RULE">%1$s</xliff:g>\"?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Eliminar"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Desconocida"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Estas opciones no se pueden modificar en este momento. Una aplicación (<xliff:g id="APP_NAME">%1$s</xliff:g>) ha activado automáticamente el modo No molestar con funcionamiento personalizado."</string>
@@ -3469,10 +3469,10 @@
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Ninguno"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Todos los días"</string>
     <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"La alarma puede anular la hora de finalización"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"La programación se desactiva cuando suena una alarma"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"La programación se desactiva si suena una alarma"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Comportamiento del modo No molestar"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Usar configuración predeterminada"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Crear opciones de configuración personalizadas para esta programación"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Crear ajustes personalizados para esta programación"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"En la programación \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-et/strings.xml b/tests/CarDeveloperOptions/res/values-et/strings.xml
index f8b5789..51976a9 100644
--- a/tests/CarDeveloperOptions/res/values-et/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-et/strings.xml
@@ -2064,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Helitugevuse nupu otsetee"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Otsetee teenus"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Lukustuskuval lubamine"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Kui otsetee on sisse lülitatud, võite hõlbustusfunktsiooni käivitamiseks hoida mõlemat helitugevuse nuppu 3 sekundit all."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Kui otsetee on sisse lülitatud, võite hõlbustusfunktsiooni käivitamiseks hoida mõlemat helitugevuse klahvi 3 sekundit all."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Suure kontrastsusega tekst"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Ekraanisuurenduse värskendus"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Ekraanisuurenduse kasutus rakenduste vahetamisel"</string>
diff --git a/tests/CarDeveloperOptions/res/values-eu/strings.xml b/tests/CarDeveloperOptions/res/values-eu/strings.xml
index bca8810..8c778bf 100644
--- a/tests/CarDeveloperOptions/res/values-eu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-eu/strings.xml
@@ -129,10 +129,10 @@
     <string name="bluetooth_show_received_files" msgid="5060846395852236652">"Jasotako fitxategiak"</string>
     <string name="bluetooth_show_files_received_via_bluetooth" msgid="1699095577431389560">"Bluetooth bidez jasotako fitxategiak"</string>
     <string name="device_picker" msgid="8345264486071697705">"Aukeratu Bluetooth bidezko gailua"</string>
-    <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu nahi du"</string>
-    <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa desaktibatu nahi du"</string>
-    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"Aplikazio batek Bluetooth konexioa aktibatu nahi du"</string>
-    <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"Aplikazio batek Bluetooth konexioa desaktibatu nahi du"</string>
+    <string name="bluetooth_ask_enablement" msgid="8716802066127746062">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu nahi du"</string>
+    <string name="bluetooth_ask_disablement" msgid="7125319551097350783">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a desaktibatu nahi du"</string>
+    <string name="bluetooth_ask_enablement_no_name" msgid="6105893027185475233">"Aplikazio batek Bluetooth-a aktibatu nahi du"</string>
+    <string name="bluetooth_ask_disablement_no_name" msgid="8648888502291681310">"Aplikazio batek Bluetooth-a desaktibatu nahi du"</string>
     <string name="bluetooth_ask_discovery" product="tablet" msgid="6871595755186170115">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak tableta Bluetooth bidezko beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
     <string name="bluetooth_ask_discovery" product="default" msgid="3388041479101348095">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak telefonoa Bluetooth bidezko beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
     <string name="bluetooth_ask_discovery_no_name" product="tablet" msgid="1472358802231150345">"Aplikazio batek tableta Bluetooth bidezko beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
@@ -141,14 +141,14 @@
     <string name="bluetooth_ask_lasting_discovery" product="default" msgid="7796723473397303412">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak telefonoa beste Bluetooth bidezko gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
     <string name="bluetooth_ask_lasting_discovery_no_name" product="tablet" msgid="5961921359655434504">"Aplikazio batek tableta beste Bluetooth bidezko gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
     <string name="bluetooth_ask_lasting_discovery_no_name" product="default" msgid="3585910858758443872">"Aplikazio batek telefonoa beste Bluetooth bidezko gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"Aplikazio batek Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"Aplikazio batek Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"Aplikazio batek Bluetooth konexioa aktibatu eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
-    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"Aplikazio batek Bluetooth konexioa aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_discovery" product="tablet" msgid="5676466923424941153">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_discovery" product="default" msgid="507088376226791063">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%2$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="tablet" msgid="1164681893121736219">"Aplikazio batek Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_discovery_no_name" product="default" msgid="2542247690119921188">"Aplikazio batek Bluetooth-a aktibatu, eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du <xliff:g id="TIMEOUT">%1$d</xliff:g> segundoz."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="tablet" msgid="7118362102769177771">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery" product="default" msgid="2577488464813970727">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak Bluetooth-a aktibatu, eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="tablet" msgid="7083038132794842691">"Aplikazio batek Bluetooth-a aktibatu, eta tableta beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
+    <string name="bluetooth_ask_enablement_and_lasting_discovery_no_name" product="default" msgid="3541668604020109525">"Aplikazio batek Bluetooth-a aktibatu eta telefonoa beste gailu batzuen aurrean ikusgai ezarri nahi du. Bluetooth-aren ezarpenetan alda dezakezu hori geroago."</string>
     <string name="bluetooth_turning_on" msgid="6935183036449748493">"Bluetooth-a aktibatzen…"</string>
     <string name="bluetooth_turning_off" msgid="9214026723789756620">"Bluetooth-a desaktibatzen…"</string>
     <string name="bluetooth_connection_permission_request" msgid="2382506002340643398">"Bluetooth bidez konektatzeko eskaera"</string>
@@ -182,7 +182,7 @@
     <string name="connected_device_connections_title" msgid="9205000271382018428">"Konexio-hobespenak"</string>
     <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Aurrez konektatutako gailuak"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"Aurretik konektatutakoak"</string>
-    <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Aktibatu da Bluetooth konexioa"</string>
+    <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Aktibatu da Bluetooth-a"</string>
     <string name="previous_connected_see_all" msgid="7237095013087310923">"Ikusi guztiak"</string>
     <string name="date_and_time" msgid="2957463607025909857">"Data eta ordua"</string>
     <string name="choose_timezone" msgid="8215332993926818147">"Aukeratu ordu-zona"</string>
@@ -1457,7 +1457,7 @@
     <string name="storage_detail_other" msgid="9164851767437306618">"Beste datu batzuk"</string>
     <string name="storage_detail_system" msgid="6784247618772153283">"Sistema"</string>
     <string name="storage_detail_explore" msgid="8206900269596580264">"Arakatu <xliff:g id="NAME">^1</xliff:g>"</string>
-    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Hauek dira \"Beste fitxategi batzuk\" atalean gordetzen diren fitxategiak: aplikazioek gordetako fitxategi partekatuak, Internetetik edo Bluetooth konexioaren bidez deskargatutakoak, Android fitxategiak, etab.\n\n<xliff:g id="NAME">^1</xliff:g> honetan ikusgai dagoen edukia ikusteko, sakatu Arakatu."</string>
+    <string name="storage_detail_dialog_other" msgid="5073511663616043370">"Hauek dira \"Beste fitxategi batzuk\" atalean gordetzen diren fitxategiak: aplikazioek gordetako fitxategi partekatuak, Internet edo Bluetooth bidez deskargatutakoak, Android-eko fitxategiak, etab.\n\n<xliff:g id="NAME">^1</xliff:g> honetan ikusgai dagoen edukia ikusteko, sakatu Arakatu."</string>
     <string name="storage_detail_dialog_system" msgid="1472572861360014226">"Android-en <xliff:g id="VERSION">%s</xliff:g>. bertsioa exekutatzeko balio duten fitxategiak daude sisteman"</string>
     <string name="storage_detail_dialog_user" msgid="1663117417635010371">"Baliteke <xliff:g id="USER_0">^1</xliff:g> erabiltzaileak argazkiak, musika, aplikazioak edo bestelako datuak gorde izatea, memorian <xliff:g id="SIZE">^2</xliff:g> hartuta. \n\nXehetasunak ikusteko, aldatu <xliff:g id="USER_1">^1</xliff:g> erabiltzailearen kontura."</string>
     <string name="storage_wizard_init_title" msgid="3407283236421089014">"Konfiguratu <xliff:g id="NAME">^1</xliff:g> memoria"</string>
@@ -1664,7 +1664,7 @@
     <string name="location_scanning_wifi_always_scanning_title" msgid="6750542206763112172">"Wifi-sareen bilaketa"</string>
     <string name="location_scanning_wifi_always_scanning_description" msgid="4956048135941851712">"Eman wifi-sareak edozein unetan bilatzeko baimena aplikazioei eta zerbitzuei, baita wifi-konexioa desaktibatuta dagoenean ere. Kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke hori, besteak beste."</string>
     <string name="location_scanning_bluetooth_always_scanning_title" msgid="196241746742607453">"Bluetooth bidezko gailuen bilaketa"</string>
-    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Eman inguruko gailuak edozein unetan bilatzeko baimena aplikazioei eta zerbitzuei, baita Bluetooth konexioa desaktibatuta dagoenean ere. Kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke hori, besteak beste."</string>
+    <string name="location_scanning_bluetooth_always_scanning_description" msgid="3796673798637848690">"Eman inguruko gailuak edozein unetan bilatzeko baimena aplikazioei eta zerbitzuei, baita Bluetooth-a desaktibatuta dagoenean ere. Kokapenean oinarritutako eginbideak eta zerbitzuak hobetzeko erabil daiteke hori, besteak beste."</string>
     <string name="managed_profile_location_services" msgid="224925483299159541">"Lanerako kokapen-zerbitzuak"</string>
     <string name="location_network_based" msgid="1535812159327454835">"Wi‑Fi eta sare mugikor bidezko kokapena"</string>
     <string name="location_neighborhood_level" msgid="8459352741296587916">"Utzi aplikazioei zure kokapena bizkorrago zehazteko Google-ren kokapen-zerbitzua erabiltzen. Kokapen-datu anonimoak bildu eta Google-ra bidaliko dira."</string>
@@ -2061,10 +2061,10 @@
     <string name="accessibility_screen_magnification_summary" msgid="3363006902079431772"><b>"Zooma aplikatzeko"</b>", sakatu pantaila bizkor hiru aldiz.\n"<ul><li>"Gora edo behera egiteko, arrastatu gutxienez bi hatz."</li>\n<li>"Zooma doitzeko, atximurkatu pantaila gutxienez bi hatzekin."</li></ul>\n\n<b>"Zooma une batez bakarrik aplikatzeko"</b>", sakatu pantaila bizkor hiru aldiz eta, hirugarren aldian, utzi hatza pantailan jarrita.\n"<ul><li>"Pantailan mugitzeko, arrastatu hatza."</li>\n<li>"Zooma aplikatzeari uzteko, altxatu hatza."</li></ul>\n\n"Zooma ezin da aplikatu ez teklatuan ez nabigazio-barran."</string>
     <string name="accessibility_screen_magnification_navbar_summary" msgid="4726360285256503132">"Lupa aktibatuta dagoenean, sakatu pantailaren behealdeko Erabilerraztasuna botoia pantaila azkar handitzeko.\n\n"<b>"Zooma aplikatzeko"</b>", sakatu Erabilerraztasuna botoia eta sakatu pantailako edozein toki.\n"<ul><li>"Gora edo behera egiteko, arrastatu gutxienez bi hatz."</li>\n<li>"Zooma doitzeko, atximurkatu pantaila gutxienez bi hatzekin."</li></ul>\n\n<b>"Zooma une batez bakarrik aplikatzeko"</b>", sakatu Erabilerraztasuna botoia eta eduki sakatuta pantailako puntu bat.\n"<ul><li>"Pantailan mugitzeko, arrastatu hatza."</li>\n<li>"Zooma aplikatzeari uzteko, altxatu hatza."</li></ul>\n\n"Zooma ezin da aplikatu ez teklatuan ez nabigazio-barran."</string>
     <string name="accessibility_screen_magnification_navbar_configuration_warning" msgid="6477234309484795550">"Erabilerraztasuna botoia labur sakatuta \"<xliff:g id="SERVICE">%1$s</xliff:g>\" aukera aktibatzen da. Lupa aplikatzeko, eduki sakatuta Erabilerraztasuna botoia eta, ondoren, hautatu lupa."</string>
-    <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Bolumen-teklen lasterbidea"</string>
+    <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Bolumen-botoien lasterbidea"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Lasterbideari esleitutako zerbitzua"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Baimendu pantaila blokeatuan"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Lasterbidea aktibatuta dagoenean, bi bolumen-teklak hiru segundoz sakatuta abiarazten da erabilerraztasun-eginbidea."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiarazten da erabilerraztasun-eginbidea."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"Kontraste handiko testua"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Eguneratu auto. pantaila-handiagotzea"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Eguneratu handiagotzea aplik. batetik bestera pasatzean."</string>
@@ -3123,7 +3123,7 @@
     <string name="keywords_assist_input" msgid="8392362788794886564">"lehenetsia, laguntzailea"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"ordaindu, lehenetsia"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"jasotako jakinarazpena"</string>
-    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb konexioa partekatu, bluetooth konexioa partekatu, wifi-gunea"</string>
+    <string name="keywords_hotspot_tethering" msgid="1723591462602613867">"usb konexioa partekatu, bluetooth bidezko konexioa partekatu, wifi-gunea"</string>
     <string name="keywords_touch_vibration" msgid="2081175517528255224">"ukipena, dardara, pantaila, sentikortasuna"</string>
     <string name="keywords_ring_vibration" msgid="4210509151866460210">"ukipena, dardara, telefonoa, deia, sentikortasuna, tonua"</string>
     <string name="keywords_notification_vibration" msgid="1077515502086745166">"ukipena, dardara, sentikortasuna"</string>
diff --git a/tests/CarDeveloperOptions/res/values-fi/strings.xml b/tests/CarDeveloperOptions/res/values-fi/strings.xml
index 659ba8a..298c467 100644
--- a/tests/CarDeveloperOptions/res/values-fi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-fi/strings.xml
@@ -3443,7 +3443,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Lisää aikapohjainen aikataulu"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Poista aikataulu"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Valitse aikataulutyyppi"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Poistetaanko sääntö <xliff:g id="RULE">%1$s</xliff:g>?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Poistetaanko tämä sääntö (<xliff:g id="RULE">%1$s</xliff:g>)?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Poista"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Tuntematon"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Näitä asetuksia ei voi muuttaa juuri nyt. Sovellus <xliff:g id="APP_NAME">%1$s</xliff:g> otti Älä häiritse ‑tilan automaattisesti käyttöön muokatulla toiminnalla."</string>
@@ -3468,11 +3468,11 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"Päivät"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Ei mitään"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Joka päivä"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Herätys voi ohittaa päättymisajan"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Aikataulu poistuu käytöstä, kun hälytys soi"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Herätys voi kumota päättymisajan"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Aikataulu menee pois päältä herätyksen yhteydessä"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Älä häiritse ‑tilan toiminta"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Käytä oletusasetuksia"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Luo tälle aikataululle omia asetuksia"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Valitse omat asetukset tälle aikataululle"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string>
@@ -3493,9 +3493,9 @@
     <string name="zen_mode_from_anyone" msgid="7778836826814131083">"Keneltä tahansa"</string>
     <string name="zen_mode_from_contacts" msgid="267034158294332688">"Vain yhteystiedoilta"</string>
     <string name="zen_mode_from_starred" msgid="7349984569117392260">"Vain tähdellä merkityiltä yhteystiedoilta"</string>
-    <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Tähdellä merkityiltä yhteyshenkilöiltä ja toistuvilta soittajilta"</string>
-    <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Yhteyshenkilöiltä ja toistuvilta soittajilta"</string>
-    <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Vain toistuvilta soittajilta"</string>
+    <string name="zen_calls_summary_starred_repeat" msgid="9191394641577678207">"Tähdellä merkityiltä yhteyshenkilöiltä ja usein soittavilta"</string>
+    <string name="zen_calls_summary_contacts_repeat" msgid="7747592096431111510">"Yhteyshenkilöiltä ja usein soittavilta"</string>
+    <string name="zen_calls_summary_repeat_only" msgid="8839703337232747964">"Vain usein soittavilta"</string>
     <string name="zen_mode_from_none" msgid="7683889985618637010">"Ei keneltäkään"</string>
     <string name="zen_mode_from_none_calls" msgid="2967739140346917546">"Älä salli puheluja"</string>
     <string name="zen_mode_from_none_messages" msgid="9069143820057833634">"Älä salli viestejä."</string>
@@ -3518,9 +3518,9 @@
     <string name="zen_mode_all_callers" msgid="4455039040077343838">"kuka tahansa"</string>
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"yhteyshenkilöt"</string>
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"tähdellä merkityt yhteyshenkilöt"</string>
-    <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Toistuvat soitot"</string>
+    <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Usein soittavat"</string>
     <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"toistuvat puhelut"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Salli toistuvat soitot"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Salli usein soittavat"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Salli puhelut: <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Salli puhelut: <xliff:g id="CALLER_TYPE">%1$s</xliff:g> ja <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"Jos sama henkilö soittaa uudelleen <xliff:g id="MINUTES">%d</xliff:g> minuutin kuluessa"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hi/strings.xml b/tests/CarDeveloperOptions/res/values-hi/strings.xml
index 180855c..63c17cb 100644
--- a/tests/CarDeveloperOptions/res/values-hi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hi/strings.xml
@@ -3442,7 +3442,7 @@
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"इवेंट का शेड्यूल जोड़ें"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"समय का शेड्यूल जोड़ें"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"शेड्यूल मिटाएं"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"शेड्यूल का प्रकार चुनें"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"किस तरह का शेड्यूल चुनना चाहते हैं"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"<xliff:g id="RULE">%1$s</xliff:g> नियम मिटाएं?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"मिटाएं"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"अज्ञात"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hr/strings.xml b/tests/CarDeveloperOptions/res/values-hr/strings.xml
index aaf929c..be961be 100644
--- a/tests/CarDeveloperOptions/res/values-hr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hr/strings.xml
@@ -409,7 +409,7 @@
     <string name="security_settings_face_enroll_introduction_message_setup" msgid="4533297059466270074">"Licem možete otključati telefon, autorizirati kupnje ili se prijaviti na aplikacije"</string>
     <string name="security_settings_face_enroll_introduction_footer_message" msgid="7764021721107723266"></string>
     <string name="security_settings_face_enroll_repeat_title" msgid="2507710348140837875">"Postavite lice u središte kruga"</string>
-    <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Budem kasnije"</string>
+    <string name="security_settings_face_enroll_enrolling_skip" msgid="4346077260378772613">"Kasnije ću"</string>
     <string name="face_add_max" msgid="8870899421165189413">"Ne možete dodati više od <xliff:g id="COUNT">%d</xliff:g> lica"</string>
     <string name="face_intro_error_max" msgid="4024147799079828937">"Dodali ste maksimalan broj lica"</string>
     <string name="face_intro_error_unknown" msgid="3241592604198351134">"Nije moguće dodati više lica"</string>
@@ -475,7 +475,7 @@
     <string name="security_settings_fingerprint_enroll_repeat_message" msgid="4434560313661204448">"Nastavite podizati prst da biste dodali različite dijelove otiska prsta"</string>
     <string name="security_settings_fingerprint_enroll_finish_title" msgid="2987918958909117821">"Otisak prsta dodan"</string>
     <string name="security_settings_fingerprint_enroll_finish_message" msgid="5862643337893923347">"Kada se prikaže ta ikona, upotrijebite otisak prsta da biste se identificirali ili odobrili kupnju"</string>
-    <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Budem kasnije"</string>
+    <string name="security_settings_fingerprint_enroll_enrolling_skip" msgid="1473280156532146933">"Kasnije ću"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_title" msgid="2816424026528101690">"Preskočiti postavljanje otiska prsta?"</string>
     <string name="setup_fingerprint_enroll_enrolling_skip_message" msgid="8139299964344809780">"Odlučili ste se za otisak prsta kao jedan od načina za otključavanje telefona. Ako sad preskočite, morat ćete ga postaviti kasnije. Postavljanje traje samo otprilike jednu minutu."</string>
     <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="tablet" msgid="1384438077720821127">"Zaštitite tablet pomoću opcije zaključavanja zaslona kako se nitko ne bi mogao njime koristiti ako ga izgubite ili ga netko ukrade. Opcija zaključavanja zaslona treba vam i za postavljanje otiska prsta. Dodirnite Odustani, a zatim postavite PIN ili odaberite neku drugu opciju zaključavanja zaslona."</string>
diff --git a/tests/CarDeveloperOptions/res/values-in/strings.xml b/tests/CarDeveloperOptions/res/values-in/strings.xml
index 307e232..f61b8a5 100644
--- a/tests/CarDeveloperOptions/res/values-in/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-in/strings.xml
@@ -1109,7 +1109,7 @@
     <string name="wifi_calling_mode_wifi_preferred_summary" msgid="8298294808362169798">"Jika Wi-Fi tidak tersedia, gunakan jaringan seluler"</string>
     <string name="wifi_calling_mode_cellular_preferred_summary" msgid="4906499810156794061">"Jika jaringan seluler tidak tersedia, gunakan Wi-Fi"</string>
     <string name="wifi_calling_mode_wifi_only_summary" msgid="6928556021002500522">"Telepon melalui Wi-Fi. Jika Wi-Fi terputus, panggilan akan berakhir."</string>
-    <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"Jika panggilan Wi-Fi aktif, ponsel dapat merutekan panggilan telepon melalui jaringan Wi-Fi atau jaringan operator, bergantung pada preferensi dan sinyal mana yang lebih kuat. Sebelum mengaktifkan fitur ini, sebaiknya tanyakan info biaya dan detail lainnya ke operator.<xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
+    <string name="wifi_calling_off_explanation" msgid="1653424723742898015">"Jika panggilan Wi-Fi aktif, ponsel dapat mengarahkan panggilan telepon melalui jaringan Wi-Fi atau jaringan operator, bergantung pada preferensi dan sinyal mana yang lebih kuat. Sebelum mengaktifkan fitur ini, sebaiknya tanyakan info biaya dan detail lainnya ke operator.<xliff:g id="ADDITIONAL_TEXT">%1$s</xliff:g>"</string>
     <string name="wifi_calling_off_explanation_2" msgid="8648609693875720408"></string>
     <string name="emergency_address_title" msgid="5779915349686787024">"Alamat Darurat"</string>
     <string name="emergency_address_summary" msgid="478668478569851714">"Digunakan sebagai lokasi Anda ketika Anda melakukan panggilan darurat melalui Wi‑Fi"</string>
diff --git a/tests/CarDeveloperOptions/res/values-is/strings.xml b/tests/CarDeveloperOptions/res/values-is/strings.xml
index b0377ee..1af76fa 100644
--- a/tests/CarDeveloperOptions/res/values-is/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-is/strings.xml
@@ -3459,8 +3459,8 @@
     <string name="zen_mode_event_rule_summary_reply_template" msgid="3917497077674876311">"Þar sem svarið er <xliff:g id="REPLY">%1$s</xliff:g>"</string>
     <string name="zen_mode_event_rule_calendar_any" msgid="155915101132859764">"Öll dagatöl"</string>
     <string name="zen_mode_event_rule_reply" msgid="9100941281268256319">"Þar sem svarið er"</string>
-    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"„Já“, „Kannski“ eða „Ekki svarað“"</string>
-    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"„Já“ eða „Kannski“"</string>
+    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"Já, Kannski eða Ekki svarað"</string>
+    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"Já eða Kannski"</string>
     <string name="zen_mode_event_rule_reply_yes" msgid="7039756546321205552">"Já"</string>
     <string name="zen_mode_rule_not_found_text" msgid="6553855397424553685">"Regla fannst ekki."</string>
     <string name="zen_mode_rule_summary_enabled_combination" msgid="8269105393636454359">"Kveikt / <xliff:g id="MODE">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-kk/strings.xml b/tests/CarDeveloperOptions/res/values-kk/strings.xml
index c802a71..6271637 100644
--- a/tests/CarDeveloperOptions/res/values-kk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-kk/strings.xml
@@ -3189,7 +3189,7 @@
     <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Кесте"</string>
     <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"Кестені пайдалану"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"Маңыздылары ғана"</string>
-    <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Тек дабылдар"</string>
+    <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Оятқыштар ғана"</string>
     <string name="zen_mode_option_no_interruptions" msgid="4723700274519260852">"Толық тыныштық"</string>
     <string name="zen_mode_summary_combination" msgid="6960111215170691605">"<xliff:g id="MODE">%1$s</xliff:g>: <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="zen_mode_visual_interruptions_settings_title" msgid="8378266552787406849">"Көрнекі мазалағыштарды бөгеу"</string>
@@ -3468,8 +3468,8 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"Күндер"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Ешқандай"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Күн сайын"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Дабыл аяқталу уақытын өзгерте алады"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Дабыл берілген кезде, кесте өшеді"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Оятқыш аяқталу уақытын өзгерте алады"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Оятқыш қосылған кезде, кесте өшеді"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\"Мазаламау\" режимі"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Әдепкі параметрлерді пайдалану"</string>
     <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Осы кесте үшін ерекше параметрлер орнату"</string>
diff --git a/tests/CarDeveloperOptions/res/values-km/strings.xml b/tests/CarDeveloperOptions/res/values-km/strings.xml
index c8b2bdb..f07f03b 100644
--- a/tests/CarDeveloperOptions/res/values-km/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-km/strings.xml
@@ -3459,8 +3459,8 @@
     <string name="zen_mode_event_rule_summary_reply_template" msgid="3917497077674876311">"នៅពេលឆ្លើយតបថា <xliff:g id="REPLY">%1$s</xliff:g>"</string>
     <string name="zen_mode_event_rule_calendar_any" msgid="155915101132859764">"ប្រតិទិនណាមួយ"</string>
     <string name="zen_mode_event_rule_reply" msgid="9100941281268256319">"នៅពេលឆ្លើយតបថា"</string>
-    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"យល់ព្រម ប្រហែល ឬមិនឆ្លើយតប"</string>
-    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"យល់ព្រម ឬប្រហែល"</string>
+    <string name="zen_mode_event_rule_reply_any_except_no" msgid="3344044163641764449">"បាទ/ចាស ប្រហែល ឬមិនឆ្លើយតប"</string>
+    <string name="zen_mode_event_rule_reply_yes_or_maybe" msgid="5042234361937256329">"បាទ/ចាស ឬប្រហែល"</string>
     <string name="zen_mode_event_rule_reply_yes" msgid="7039756546321205552">"បាទ/ចាស"</string>
     <string name="zen_mode_rule_not_found_text" msgid="6553855397424553685">"រកមិនឃើញច្បាប់ទេ។"</string>
     <string name="zen_mode_rule_summary_enabled_combination" msgid="8269105393636454359">"បើក / <xliff:g id="MODE">%1$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ky/strings.xml b/tests/CarDeveloperOptions/res/values-ky/strings.xml
index be41ac2..d694743 100644
--- a/tests/CarDeveloperOptions/res/values-ky/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ky/strings.xml
@@ -113,7 +113,7 @@
     <string name="bluetooth_disconnect_all_profiles" product="device" msgid="4707569949253450208">"Түзмөгүңүз <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүнөн ажыратылат."</string>
     <string name="bluetooth_disconnect_dialog_ok" msgid="4183522987246110145">"Ажыратуу"</string>
     <string name="bluetooth_empty_list_user_restricted" msgid="3616298363281495777">"Bluetooth жөндөөлөрүн өзгөртүүгө уруксатыңыз жок."</string>
-    <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"Жаңы түзмөктү жупташтыруу"</string>
+    <string name="bluetooth_pairing_pref_title" msgid="2904954138013884029">"Жаңы түзмөк кошуу"</string>
     <string name="bluetooth_is_visible_message" msgid="6341088682252805612">"Bluetooth жөндөөлөрү ачылып турганда <xliff:g id="DEVICE_NAME">%1$s</xliff:g> жакын арадагы түзмөктөргө көрүнөт."</string>
     <string name="bluetooth_footer_mac_message" product="default" msgid="335341476746836260">"Телефондун Bluetooth дареги: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
     <string name="bluetooth_footer_mac_message" product="tablet" msgid="6033609611245782463">"Планшеттин Bluetooth дареги: <xliff:g id="BLUETOOTH_MAC_ADDRESS">%1$s</xliff:g>"</string>
@@ -165,7 +165,7 @@
     <string name="bluetooth_device_name_summary" msgid="8661066392056595005">"Башка түзмөктөргө \"<xliff:g id="DEVICE_NAME">^1</xliff:g>\" деп көрүнөт"</string>
     <string name="bluetooth_off_footer" msgid="7658444560543730571">"Башка түзмөктөргө туташуу үчүн Bluetooth\'ду күйгүзүңүз."</string>
     <string name="bluetooth_paired_device_title" msgid="8361860197780425286">"Түзмөктөрүңүз"</string>
-    <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"Жаңы түзмөктү жупташтыруу"</string>
+    <string name="bluetooth_pairing_page_title" msgid="9053463656712597709">"Жаңы түзмөктү байланыштыруу"</string>
     <string name="bluetooth_pref_summary" product="tablet" msgid="3601662966604648212">"Планшетиңизге жакын жердеги Bluetooth түзмөктөрү менен байланышууга уруксат бериңиз"</string>
     <string name="bluetooth_pref_summary" product="device" msgid="2286727776570956969">"Түзмөгүңүзгө жакын жердеги Bluetooth түзмөктөрү менен байланышууга уруксат бериңиз"</string>
     <string name="bluetooth_pref_summary" product="default" msgid="863659221858781186">"Телефонуңузду жакын жердеги Bluetooth түзмөктөрүнө байланыштырат."</string>
@@ -180,7 +180,7 @@
     <string name="connected_device_saved_title" msgid="8270136893488475163">"Сакталган түзмөктөр"</string>
     <string name="connected_device_add_device_summary" msgid="7960491471270158891">"Bluetooth жупташтыруу үчүн күйгүзүлөт"</string>
     <string name="connected_device_connections_title" msgid="9205000271382018428">"Туташуу параметрлери"</string>
-    <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Мурунтан туташкан түзмөктөр"</string>
+    <string name="connected_device_previously_connected_title" msgid="225918223397410428">"Буга чейин туташкан түзмөктөр"</string>
     <string name="connected_device_previously_connected_screen_title" msgid="2018789662358162716">"Мурда туташкан"</string>
     <string name="connected_device_bluetooth_turned_on_toast" msgid="4652326177920814476">"Bluetooth күйгүзүлдү"</string>
     <string name="previous_connected_see_all" msgid="7237095013087310923">"Баарын көрүү"</string>
@@ -994,7 +994,7 @@
     <string name="lost_internet_access_text" msgid="8962010031520731813">"Wi-Fi байланышы начар болгондо, ар дайым мобилдик тармакка өтө аласыз. Дайындардын өткөрүлгөндүгү үчүн акы алынышы мүмкүн."</string>
     <string name="lost_internet_access_switch" msgid="9218006455779873700">"Мобилдик түзмөккө которуу"</string>
     <string name="lost_internet_access_cancel" msgid="6577871064062518744">"Wi-Fi тармагында калуу"</string>
-    <string name="lost_internet_access_persist" msgid="6368659013482055611">"Кайра көрсөтүлбөсүн"</string>
+    <string name="lost_internet_access_persist" msgid="6368659013482055611">"Кайра көрүнбөсүн"</string>
     <string name="wifi_connect" msgid="5653612760223533650">"Туташуу"</string>
     <string name="wifi_turned_on_message" msgid="3377779146238242894">"Wi-Fi күйгүзүлдү"</string>
     <!-- no translation found for wifi_connected_to_message (2875589636437599620) -->
@@ -3417,7 +3417,7 @@
     <string name="notification_toggle_on" msgid="5119816745741139542">"Күйүк"</string>
     <string name="notification_toggle_off" msgid="5289843670514922751">"Өчүк"</string>
     <string name="app_notification_block_title" msgid="7898269373875294367">"Баарын бөгөттөө"</string>
-    <string name="app_notification_block_summary" msgid="4502146897785692336">"Бул билдирмелер эч качан көрсөтүлбөсүн"</string>
+    <string name="app_notification_block_summary" msgid="4502146897785692336">"Бул билдирмелер эч качан көрүнбөсүн"</string>
     <string name="notification_content_block_title" msgid="2805138591864484587">"Билдирмелер"</string>
     <string name="notification_content_block_summary" msgid="2743896875255591743">"Билдирмелер эч качан фондо же тышкы түзмөктөрдө көрүнбөсүн"</string>
     <string name="notification_badge_title" msgid="8989086619255666442">"Билдирмелер белгиси көрүнсүн"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mk/strings.xml b/tests/CarDeveloperOptions/res/values-mk/strings.xml
index 94c0d71..8aa9d8a 100644
--- a/tests/CarDeveloperOptions/res/values-mk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mk/strings.xml
@@ -1742,7 +1742,7 @@
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Телефонот е ресетиран на фабрички поставки. За да го користите, внесете го претходниот PIN."</string>
     <string name="lockpassword_confirm_your_password_details_frp" msgid="3239944795659418737">"Телефонот е ресетиран на фабрички поставки. За да го користите, внесете ја претходната лозинка."</string>
     <string name="lockpassword_confirm_your_pattern_header_frp" msgid="3290569334665839860">"Потврдете ја шемата"</string>
-    <string name="lockpassword_confirm_your_pin_header_frp" msgid="8520474869079710782">"Потврди PIN"</string>
+    <string name="lockpassword_confirm_your_pin_header_frp" msgid="8520474869079710782">"Потврдете го PIN-от"</string>
     <string name="lockpassword_confirm_your_password_header_frp" msgid="7326670978891793470">"Потврдете ја лозинката"</string>
     <string name="lockpassword_invalid_pin" msgid="3059022215815900137">"Погрешен PIN"</string>
     <string name="lockpassword_invalid_password" msgid="8374331995318204099">"Погрешна лозинка"</string>
@@ -3443,7 +3443,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Додај распоред за време"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Избришете го распоредот"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Изберете тип распоред"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Избриши правило за „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Да се избрише правилото „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Избриши"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Непознато"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Поставкиве не може да се променат во моментов. Дадена апликација (<xliff:g id="APP_NAME">%1$s</xliff:g>) го вклучи режимот „Не вознемирувај“ автоматски со приспособено однесување."</string>
diff --git a/tests/CarDeveloperOptions/res/values-ml/strings.xml b/tests/CarDeveloperOptions/res/values-ml/strings.xml
index 2f0c29a..f068854 100644
--- a/tests/CarDeveloperOptions/res/values-ml/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ml/strings.xml
@@ -3468,7 +3468,7 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"ദിവസം"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"ഒന്നുമില്ല"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"എല്ലാ ദിവസവും"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"അലാറമിന് അവസാനിക്കുന്ന സമയം അസാധുവാക്കാൻ കഴിയും"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"അലാറത്തിന് അവസാനിക്കുന്ന സമയം അസാധുവാക്കാൻ കഴിയും"</string>
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"ഒരു അലാറം റിംഗ് ചെയ്യുമ്പോൾ, ഷെഡ്യൂൾ ഓഫാകുന്നു"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"\'ശല്യപ്പെടുത്തരുത്\' എന്ന് അർത്ഥമാക്കുന്ന പെരുമാറ്റം"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"ഡിഫോൾട്ട് ക്രമീകരണം ഉപയോഗിക്കുക"</string>
diff --git a/tests/CarDeveloperOptions/res/values-mn/strings.xml b/tests/CarDeveloperOptions/res/values-mn/strings.xml
index 6700a5a..dd5be6f 100644
--- a/tests/CarDeveloperOptions/res/values-mn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mn/strings.xml
@@ -3555,7 +3555,7 @@
     <string name="screen_pinning_title" msgid="578020318289781102">"Дэлгэц тогтоох"</string>
     <string name="screen_pinning_description" msgid="3814537379086412278">"Энэ тохиргоо асаалттай үед та одоогийн дэлгэцийг тогтоохоо болих хүртлээ үргэлжлүүлэн харуулахын тулд дэлгэц тогтоох онцлогийг ашиглах боломжтой.\n\nДэлгэц тогтоох онцлогийг ашиглахын тулд:\n\n1. Дэлгэц тогтоох онцлог асаалттай эсэхийг шалгах\n\n2. Тоймыг нээх\n\n3. Дэлгэцийн дээд хэсгийн аппын дүрс тэмдгийг товшиж Тогтоох гэснийг товшино уу"</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
-    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
+    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Бэхэлснийг болиулахаасаа өмнө PIN асуух"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Unpinning хийх үед төхөөрөмжийг түгжинэ"</string>
     <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Энэ ажлын профайлыг удирдагч нь:"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ne/strings.xml b/tests/CarDeveloperOptions/res/values-ne/strings.xml
index 59d7881..dc7e25b 100644
--- a/tests/CarDeveloperOptions/res/values-ne/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ne/strings.xml
@@ -4269,7 +4269,7 @@
     <string name="storage_manager_indicator_on" msgid="5295306384982062320">"सक्रिय"</string>
     <string name="install_type_instant" msgid="6248487669862821874">"तात्कालिक एप"</string>
     <string name="automatic_storage_manager_deactivation_warning" msgid="7867793739491286374">"भण्डारण व्यवस्थापक निष्क्रिय पार्ने हो?"</string>
-    <string name="storage_movies_tv" msgid="7282484273991655296">"चलचित्र तथा TV एपहरू"</string>
+    <string name="storage_movies_tv" msgid="7282484273991655296">"चलचित्र तथा टिभी एपहरू"</string>
     <string name="carrier_provisioning" msgid="3309125279191534469">"सेवा प्रदायकको प्रावधान सम्बन्धी जानकारी"</string>
     <string name="trigger_carrier_provisioning" msgid="6284005970057901477">"सेवा प्रदायकको प्रावधानलाई ट्रिगर गर्नुहोस्"</string>
     <string name="zen_suggestion_title" msgid="2134699720214231950">"बाधा नपुर्‍याउनुहोस्‌ नामक सेवालाई अद्यावधिक गर्नुहोस्‌"</string>
diff --git a/tests/CarDeveloperOptions/res/values-nl/strings.xml b/tests/CarDeveloperOptions/res/values-nl/strings.xml
index 7c1caef..a901631 100644
--- a/tests/CarDeveloperOptions/res/values-nl/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-nl/strings.xml
@@ -355,7 +355,7 @@
     <string name="security_enable_widgets_title" msgid="1701510007926738088">"Widgets inschakelen"</string>
     <string name="security_enable_widgets_disabled_summary" msgid="4408176087132339331">"Uitgeschakeld door beheerder"</string>
     <string name="lockdown_settings_title" msgid="4534779922580115990">"Lockdown-optie weergeven"</string>
-    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Optie voor aan/uit-knop weergeven waarmee Smart Lock, ontgrendeling via vingerafdruk en meldingen op het vergrendelingsscherm worden uitgeschakeld."</string>
+    <string name="lockdown_settings_summary" msgid="7270756909878256174">"Optie voor aan/uit-knop weergeven waarmee Smart Lock, ontgrendeling via vingerafdruk en meldingen op het vergrendelscherm worden uitgeschakeld."</string>
     <string name="trust_agents_extend_unlock_title" msgid="3582017561316089951">"Ontgrendelen verlengen voor trust agents"</string>
     <string name="trust_agents_extend_unlock_summary" msgid="3543997596586078084">"Indien ingeschakeld houden trust agents je apparaat langer ontgrendeld, maar hiermee kan een vergrendeld apparaat niet meer worden ontgrendeld."</string>
     <string name="trust_lost_locks_screen_title" msgid="3094736590690459372">"Scherm vergr. als vertrouwen kwijt is"</string>
@@ -364,7 +364,7 @@
     <string name="owner_info_settings_status" msgid="8049975536717685126">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
     <string name="owner_info_settings_edit_text_hint" msgid="2250029417257939706">"Bijvoorbeeld \'Android van Jan\'."</string>
     <string name="user_info_settings_title" msgid="1125111518759995748">"Gebruikersgegevens"</string>
-    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Profielinfo weergeven op vergrendelingsscherm"</string>
+    <string name="show_profile_info_on_lockscreen_label" msgid="5204282771893683026">"Profielinfo weergeven op vergrendelscherm"</string>
     <string name="profile_info_settings_title" msgid="4855892878512562551">"Profielinfo"</string>
     <string name="Accounts_settings_title" msgid="7901374987121953746">"Accounts"</string>
     <string name="location_settings_title" msgid="2707201457572301030">"Locatie"</string>
@@ -382,7 +382,7 @@
     <string name="decryption_settings_summary" product="default" msgid="7401802133199522441">"Telefoon niet gecodeerd"</string>
     <string name="encryption_and_credential_settings_summary" product="tablet" msgid="8170667308598998791">"Apparaat versleuteld"</string>
     <string name="decryption_settings_summary" product="tablet" msgid="7524119945312453569">"Apparaat niet gecodeerd"</string>
-    <string name="lockscreen_settings_title" msgid="1221505938891948413">"Weergave op vergrendelingsscherm"</string>
+    <string name="lockscreen_settings_title" msgid="1221505938891948413">"Weergave op vergrendelscherm"</string>
     <string name="lockscreen_settings_what_to_show_category" msgid="3133378945821488654">"Wat wordt weergegeven"</string>
     <string name="security_settings_summary" msgid="5210109100643223686">"\'Mijn locatie\', schermontgrendeling, sim- en certificaatopslagvergrendeling instellen"</string>
     <string name="cdma_security_settings_summary" msgid="1783066617800041869">"\'Mijn locatie\' instellen, scherm ontgrendelen, certificaatopslag vergrendelen"</string>
@@ -2116,16 +2116,16 @@
     <string name="enable_quick_setting" msgid="1580451877998661255">"Weergeven in Snelle instellingen"</string>
     <string name="daltonizer_type" msgid="6890356081036026791">"Correctiemodus"</string>
     <plurals name="accessibilty_autoclick_preference_subtitle_extremely_short_delay" formatted="false" msgid="3810676455925024813">
-      <item quantity="other">Extreem korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
-      <item quantity="one">Extreem korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
+      <item quantity="other">Extreem kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
+      <item quantity="one">Extreem kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
     </plurals>
     <plurals name="accessibilty_autoclick_preference_subtitle_very_short_delay" formatted="false" msgid="8720846747098057703">
-      <item quantity="other">Zeer korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
-      <item quantity="one">Zeer korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
+      <item quantity="other">Zeer kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
+      <item quantity="one">Zeer kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
     </plurals>
     <plurals name="accessibilty_autoclick_preference_subtitle_short_delay" formatted="false" msgid="4311889107742293108">
-      <item quantity="other">Korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
-      <item quantity="one">Korte vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
+      <item quantity="other">Kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
+      <item quantity="one">Kleine vertraging (<xliff:g id="CLICK_DELAY_LABEL_0">%1$d</xliff:g> ms)</item>
     </plurals>
     <plurals name="accessibilty_autoclick_preference_subtitle_long_delay" formatted="false" msgid="285663535113656440">
       <item quantity="other">Lange vertraging (<xliff:g id="CLICK_DELAY_LABEL_1">%1$d</xliff:g> ms)</item>
@@ -2561,7 +2561,7 @@
     <string name="backup_inactive_title" msgid="5513496915638307750">"Back-upservice is niet actief"</string>
     <string name="backup_configure_account_default_summary" msgid="5718298066335006412">"Er is momenteel geen account ingesteld voor het opslaan van back-upgegevens"</string>
     <string name="backup_erase_dialog_title" msgid="8178424339104463014"></string>
-    <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Weet je zeker dat je het maken van back-ups van je wifi-wachtwoorden, bladwijzers, andere instellingen en app-gegevens wilt stoppen en alle kopieën op Google-servers wilt wissen?"</string>
+    <string name="backup_erase_dialog_message" msgid="8767843355330070902">"Weet je zeker dat je het maken van back-ups van je wifi-wachtwoorden, bookmarks, andere instellingen en app-gegevens wilt stoppen en alle kopieën op Google-servers wilt wissen?"</string>
     <string name="fullbackup_erase_dialog_message" msgid="2588536036471144070">"Wil je stoppen met het maken van back-ups van apparaatgegevens (zoals wifi-wachtwoorden en gespreksgeschiedenis) en app-gegevens (zoals instellingen en bestanden opgeslagen door apps), en alle kopieën op externe servers wissen?"</string>
     <string name="fullbackup_data_summary" msgid="406274198094268556">"Automatisch op afstand een back-up maken van apparaatgegevens (zoals wifi-wachtwoorden en gespreksgeschiedenis) en app-gegevens (zoals instellingen en bestanden opgeslagen door apps).\n\nAls je de functie voor automatische back-ups inschakelt, worden apparaat- en app-gegevens periodiek op afstand opgeslagen. App-gegevens kunnen gegevens omvatten die een app heeft opgeslagen (op basis van de instellingen van de ontwikkelaar), waaronder potentieel gevoelige gegevens als contacten, berichten en foto\'s."</string>
     <string name="device_admin_settings_title" msgid="2074319456047334589">"Instellingen voor apparaatbeheer"</string>
@@ -2881,8 +2881,8 @@
     <string name="user_cannot_manage_message" product="default" msgid="915260531390608092">"Alleen de eigenaar van de telefoon kan gebruikers beheren."</string>
     <string name="user_cannot_add_accounts_message" msgid="5993561303748749097">"Beperkte profielen kunnen geen accounts toevoegen"</string>
     <string name="user_remove_user_menu" msgid="3505139157217459864">"<xliff:g id="USER_NAME">%1$s</xliff:g> verwijderen van dit apparaat"</string>
-    <string name="user_lockscreen_settings" msgid="3820813814848394568">"Instellingen voor vergrendelingsscherm"</string>
-    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Gebruikers toevoegen vanaf vergrendelingsscherm"</string>
+    <string name="user_lockscreen_settings" msgid="3820813814848394568">"Instellingen voor vergrendelscherm"</string>
+    <string name="user_add_on_lockscreen_menu" msgid="5211604808199585774">"Gebruikers toevoegen vanaf vergrendelscherm"</string>
     <string name="user_new_user_name" msgid="3880395219777884838">"Nieuwe gebruiker"</string>
     <string name="user_new_profile_name" msgid="3074939718101489937">"Nieuw profiel"</string>
     <string name="user_confirm_remove_self_title" msgid="6739480453680217543">"Wil je jezelf verwijderen?"</string>
@@ -3107,8 +3107,8 @@
     <string name="keywords_financial_apps_sms_access" msgid="3236014691838121857">"financiële app, sms, toegang, recht, toestemming"</string>
     <string name="keywords_systemui_theme" msgid="9150908170417305866">"donker thema"</string>
     <string name="keywords_device_feedback" msgid="6948977907405738490">"bug"</string>
-    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Inactief scherm, vergrendelingsscherm"</string>
-    <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"melding, meldingen op vergrendelingsscherm"</string>
+    <string name="keywords_ambient_display_screen" msgid="5873935693887583428">"Inactief scherm, vergrendelscherm"</string>
+    <string name="keywords_lock_screen_notif" msgid="4914337222856805463">"melding, meldingen op vergrendelscherm"</string>
     <string name="keywords_face_settings" msgid="4117345666006836599">"gezicht"</string>
     <string name="keywords_fingerprint_settings" msgid="902902368701134163">"vingerafdruk, vingerafdruk toevoegen"</string>
     <string name="keywords_display_auto_brightness" msgid="1810596220466483996">"scherm dimmen, touchscreen, batterij, slimme helderheid, dynamische helderheid"</string>
@@ -3116,10 +3116,10 @@
     <string name="keywords_auto_rotate" msgid="4320791369951647513">"roteren, draaien, omdraaien, rotatie, portret, landschap, oriëntatie, verticaal, horizontaal, staand, liggend"</string>
     <string name="keywords_system_update_settings" msgid="4419971277998986067">"upgrade, android"</string>
     <string name="keywords_zen_mode_settings" msgid="4103819458182535493">"dnd, schema, meldingen, blokkeren, stil, trillen, slapen, werken, focus, geluid, dempen, dag, weekdag, weekend, doordeweekse avond, evenement, afspraak"</string>
-    <string name="keywords_screen_timeout" msgid="4328381362313993666">"scherm, vergrendelingstijd, time-out, vergrendelingsscherm"</string>
+    <string name="keywords_screen_timeout" msgid="4328381362313993666">"scherm, vergrendelingstijd, time-out, vergrendelscherm"</string>
     <string name="keywords_storage_settings" msgid="6422454520424236476">"geheugen, cache, gegevens, wissen, verwijderen, vrij, vrijmaken, ruimte"</string>
     <string name="keywords_bluetooth_settings" msgid="1152229891590622822">"verbonden, apparaat, hoofdtelefoon, koptelefoon, headset, speaker, luidspreker, draadloos, koppelen, oordoppen, oordopjes, muziek, media"</string>
-    <string name="keywords_wallpaper" msgid="7665778626293643625">"achtergrond, scherm, vergrendelingsscherm, thema"</string>
+    <string name="keywords_wallpaper" msgid="7665778626293643625">"achtergrond, scherm, vergrendelscherm, thema"</string>
     <string name="keywords_assist_input" msgid="8392362788794886564">"standaard, assistent"</string>
     <string name="keywords_default_payment_app" msgid="845369409578423996">"betaling, standaard"</string>
     <string name="keywords_ambient_display" msgid="8835182491798487184">"binnenkomende melding"</string>
@@ -3319,7 +3319,7 @@
     <string name="swipe_direction_ltr" msgid="944932514821822709">"Veeg naar rechts om te sluiten of naar links voor het menu"</string>
     <string name="swipe_direction_rtl" msgid="4521416787262888813">"Veeg naar links om te sluiten of naar rechts voor het menu"</string>
     <string name="notification_pulse_title" msgid="4861418327614907116">"Knipperlicht"</string>
-    <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Op vergrendelingsscherm"</string>
+    <string name="lock_screen_notifications_title" msgid="6889072265118747835">"Op vergrendelscherm"</string>
     <string name="locked_work_profile_notification_title" msgid="8307025804986190658">"Als werkprofiel is vergrendeld"</string>
     <string name="lock_screen_notifications_summary_show" msgid="5788874994455257378">"Content van alle meldingen weergeven"</string>
     <string name="lock_screen_notifications_summary_hide" msgid="3668806866535260143">"Gevoelige content verbergen"</string>
@@ -3424,7 +3424,7 @@
     <string name="notification_channel_badge_title" msgid="8228215248332054612">"Meldingsstipje weergeven"</string>
     <string name="app_notification_override_dnd_title" msgid="1757042206738172601">"\'Niet storen\' negeren"</string>
     <string name="app_notification_override_dnd_summary" msgid="3152957611171210980">"Deze meldingen nog steeds ontvangen, ook wanneer \'Niet storen\' is ingeschakeld"</string>
-    <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Op vergrendelingsscherm"</string>
+    <string name="app_notification_visibility_override_title" msgid="2349335170165637672">"Op vergrendelscherm"</string>
     <string name="app_notification_row_banned" msgid="2079325338122151677">"Geblokkeerd"</string>
     <string name="app_notification_row_priority" msgid="432299064888787236">"Prioriteit"</string>
     <string name="app_notification_row_sensitive" msgid="4919671519227722958">"Gevoelig"</string>
@@ -3607,8 +3607,8 @@
     <string name="notifications_disabled" msgid="316658185757688983">"Uit"</string>
     <string name="notifications_partly_blocked" msgid="6330451240669068819">"<xliff:g id="COUNT_0">%1$d</xliff:g> van <xliff:g id="COUNT_1">%2$d</xliff:g> categorieën uit"</string>
     <string name="notifications_silenced" msgid="538923056987616372">"Zonder geluid"</string>
-    <string name="notifications_redacted" msgid="308836040236690014">"Gevoelige content niet op vergrendelingsscherm"</string>
-    <string name="notifications_hidden" msgid="3665505522897010205">"Niet op vergrendelingsscherm"</string>
+    <string name="notifications_redacted" msgid="308836040236690014">"Gevoelige content niet op vergrendelscherm"</string>
+    <string name="notifications_hidden" msgid="3665505522897010205">"Niet op vergrendelscherm"</string>
     <string name="notifications_priority" msgid="8849045645983017929">"\'Niet storen\' overschreven"</string>
     <string name="notifications_summary_divider" msgid="3148951310482572028">" / "</string>
     <string name="notification_summary_level" msgid="309162160355022027">"Niveau %d"</string>
@@ -4062,7 +4062,7 @@
     <string name="button_confirm_convert_fbe" msgid="419832223125147297">"Wissen en converteren"</string>
     <string name="reset_shortcut_manager_throttling" msgid="1912184636360233397">"Rate limiting van ShortcutManager resetten"</string>
     <string name="reset_shortcut_manager_throttling_complete" msgid="2932990541160593632">"De rate limiting van ShortcutManager is gereset."</string>
-    <string name="notification_suggestion_title" msgid="3292107671498148560">"Informatie op vergrendelingsscherm beheren"</string>
+    <string name="notification_suggestion_title" msgid="3292107671498148560">"Informatie op vergrendelscherm beheren"</string>
     <string name="notification_suggestion_summary" msgid="6516827892359614597">"Content van meldingen weergeven of verbergen"</string>
     <string name="page_tab_title_summary" msgid="4824744863994538006">"Alle"</string>
     <string name="page_tab_title_support" msgid="5569262185010367870">"Tips en ondersteuning"</string>
diff --git a/tests/CarDeveloperOptions/res/values-or/strings.xml b/tests/CarDeveloperOptions/res/values-or/strings.xml
index 17e330b..f03cb53 100644
--- a/tests/CarDeveloperOptions/res/values-or/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-or/strings.xml
@@ -2290,8 +2290,8 @@
     <string name="battery_tip_dialog_message" product="device" msgid="6348123094674390337">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ସାଧାରଣ ତୁଳନାରେ ଅଧିକ ବ୍ୟବହାର କରାଯାଇଛି। ଆଶା କରାଯାଉଥିବା ସମୟଠାରୁ ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ଶୀଘ୍ର ସରି ଯାଇପାରେ।\n\nପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବା ପରଠାରୁ ଅଧିକ ବ୍ୟବହୃତ ଆପ୍ସ।"</string>
     <string name="battery_tip_dialog_message_footer" msgid="1118827395267487197">"ଉଚ୍ଚ-ଶକ୍ତି ପୃଷ୍ଟଭୂମୀ କାର୍ଯ୍ୟ ଅନ୍ତର୍ଭୁକ୍ତ କରେ"</string>
     <plurals name="battery_tip_restrict_title" formatted="false" msgid="7140926804142734420">
-      <item quantity="other">%1$dଟି ଆପ୍‌କୁ ଅବରୋଧ କରନ୍ତୁ</item>
-      <item quantity="one">%1$dଟି ଆପ୍‌କୁ ଅବରୋଧ କରନ୍ତୁ</item>
+      <item quantity="other">%1$dଟି ଆପ୍‌କୁ ପ୍ରତିବନ୍ଧିତ କରନ୍ତୁ</item>
+      <item quantity="one">%1$dଟି ଆପ୍‌କୁ ପ୍ରତିବନ୍ଧିତ କରନ୍ତୁ</item>
     </plurals>
     <plurals name="battery_tip_restrict_handled_title" formatted="false" msgid="5509363095891806748">
       <item quantity="other">%2$dଟି ଆପ୍‌କୁ ସମ୍ପ୍ରତି ପ୍ରତିବନ୍ଧିତ କରାଯାଇଛି</item>
diff --git a/tests/CarDeveloperOptions/res/values-ru/strings.xml b/tests/CarDeveloperOptions/res/values-ru/strings.xml
index d6b3ecc..2e9c569 100644
--- a/tests/CarDeveloperOptions/res/values-ru/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ru/strings.xml
@@ -1776,7 +1776,7 @@
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"Введите PIN-код"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"Введите пароль устройства"</string>
     <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"Укажите графический ключ от рабочего профиля"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Введите PIN-код рабочего профиля"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"Для дополнительной защиты введите PIN-код рабочего профиля."</string>
     <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"Введите пароль от рабочего профиля"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"Настройки вашего телефона были сброшены. Чтобы использовать его, введите свой прежний графический ключ."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"Настройки вашего телефона были сброшены. Чтобы использовать его, введите свой прежний PIN-код."</string>
@@ -3663,7 +3663,7 @@
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Запрашивать графический ключ"</string>
     <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Запрашивать PIN-код"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Запрашивать пароль"</string>
-    <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Блокировать устройство при откл. блокировки в приложении"</string>
+    <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Блокировать устройство при отключении функции"</string>
     <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Профилем управляет"</string>
     <string name="managing_admin" msgid="3212584016377581608">"Управляется <xliff:g id="ADMIN_APP_LABEL">%s</xliff:g>"</string>
     <string name="experimental_preference" msgid="5903223408406906322">"(экспериментальная настройка)"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sk/strings.xml b/tests/CarDeveloperOptions/res/values-sk/strings.xml
index 0d97f16..6787582 100644
--- a/tests/CarDeveloperOptions/res/values-sk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sk/strings.xml
@@ -3568,7 +3568,7 @@
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Plán sa vypne, keď zazvoní budík"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Správanie režimu bez vyrušení"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Použiť predvolené nastavenia"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Vytvorte si vlastné nastavenia tohto plánu"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Vytvoriť si vlastné nastavenia tohto plánu"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"V rámci plánu <xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sr/strings.xml b/tests/CarDeveloperOptions/res/values-sr/strings.xml
index edf510e..cf41c11 100644
--- a/tests/CarDeveloperOptions/res/values-sr/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sr/strings.xml
@@ -3491,7 +3491,7 @@
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"Додајте временски распоред"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"Избриши распоред"</string>
     <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"Одаберите тип распореда"</string>
-    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Желите ли да избришете правило „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
+    <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"Желите да избришете правило „<xliff:g id="RULE">%1$s</xliff:g>“?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"Избриши"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"Непознато"</string>
     <string name="zen_mode_app_set_behavior" msgid="8597398780262575571">"Ова подешавања тренутно не могу да се мењају. Апликација (<xliff:g id="APP_NAME">%1$s</xliff:g>) је аутоматски укључила режим Не узнемиравај са прилагођеним понашањем."</string>
diff --git a/tests/CarDeveloperOptions/res/values-sv/strings.xml b/tests/CarDeveloperOptions/res/values-sv/strings.xml
index 68c7e34..e17d281 100644
--- a/tests/CarDeveloperOptions/res/values-sv/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sv/strings.xml
@@ -3183,10 +3183,10 @@
     <string name="zen_mode_rule_name_edit" msgid="5479435215341745578">"Redigera"</string>
     <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"Scheman"</string>
     <string name="zen_mode_automatic_rule_settings_page_title" msgid="5272888746413504692">"Schema"</string>
-    <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"Schemaläggning"</string>
+    <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"Schemalägg"</string>
     <string name="zen_mode_automation_suggestion_title" msgid="4921779962633710347">"Stäng av mobilljud vid vissa tider"</string>
     <string name="zen_mode_automation_suggestion_summary" msgid="2709837472884371037">"Ange regler för Stör ej"</string>
-    <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Schemaläggning"</string>
+    <string name="zen_mode_schedule_title" msgid="5275268813192802631">"Schemalägg"</string>
     <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"Använd schema"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"Bara prioriterade"</string>
     <string name="zen_mode_option_alarms" msgid="4843278125235203076">"Endast alarm"</string>
@@ -3520,7 +3520,7 @@
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"stjärnmärkta kontakter"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Återuppringning"</string>
     <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"när någon ringer flera gånger"</string>
-    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Tillåt återuppringning"</string>
+    <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Tillåt upprepade samtal"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Tillåt från <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Tillåt från <xliff:g id="CALLER_TYPE">%1$s</xliff:g> och <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
     <string name="zen_mode_repeat_callers_summary" msgid="1752513516040525545">"Om samma person ringer en gång till inom en tidsperiod på <xliff:g id="MINUTES">%d</xliff:g> minuter"</string>
@@ -3557,7 +3557,7 @@
     <string name="screen_pinning_title" msgid="578020318289781102">"Fästa skärmen"</string>
     <string name="screen_pinning_description" msgid="3814537379086412278">"När den här inställningen är aktiverad kan du fästa skärmen om du vill att den aktuella skärmen ska visas tills du lossar den.\n\nSå här fäster du skärmen:\n\n1. Kontrollera att funktionen för att fästa skärmen är på.\n\n2. Öppna översikten\n\n3. Tryck på appikonen högst upp på skärmen och sedan på Fäst."</string>
     <string name="screen_pinning_unlock_pattern" msgid="1060334707088339444">"Kräv grafiskt lösenordet innan skärmen lossas"</string>
-    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Be om pinkod innan skärmen lossas"</string>
+    <string name="screen_pinning_unlock_pin" msgid="1441705536015645023">"Be om pinkod innan appen lossas"</string>
     <string name="screen_pinning_unlock_password" msgid="1017776884000170841">"Be om lösenord innan skärmen lossas"</string>
     <string name="screen_pinning_unlock_none" msgid="9183040569733226911">"Lås enheten när skärmen lossas"</string>
     <string name="opening_paragraph_delete_profile_unknown_company" msgid="2350380017136403670">"Den här jobbprofilen hanteras av:"</string>
diff --git a/tests/CarDeveloperOptions/res/values-sw/strings.xml b/tests/CarDeveloperOptions/res/values-sw/strings.xml
index b665336..dc5f5f4 100644
--- a/tests/CarDeveloperOptions/res/values-sw/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-sw/strings.xml
@@ -3519,7 +3519,7 @@
     <string name="zen_mode_contacts_callers" msgid="3116829245339716399">"anwani"</string>
     <string name="zen_mode_starred_callers" msgid="1317376207713013472">"anwani zenye nyota"</string>
     <string name="zen_mode_repeat_callers" msgid="1435309867554692340">"Wanaorudia kupiga simu"</string>
-    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"waliopiga simu mara kadhaa"</string>
+    <string name="zen_mode_repeat_callers_list" msgid="2750270907597457279">"wanaorudia kupiga simu"</string>
     <string name="zen_mode_repeat_callers_title" msgid="7192952181541813487">"Ruhusu wanaorudia kupiga simu"</string>
     <string name="zen_mode_calls_summary_one" msgid="8327371053236689649">"Ruhusu kutoka kwa <xliff:g id="CALLER_TYPE">%1$s</xliff:g>"</string>
     <string name="zen_mode_calls_summary_two" msgid="9017678770532673578">"Ruhusu kutoka kwa <xliff:g id="CALLER_TYPE">%1$s</xliff:g> na <xliff:g id="CALLERT_TPYE">%2$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-ta/strings.xml b/tests/CarDeveloperOptions/res/values-ta/strings.xml
index 018bfc0..ce10d08 100644
--- a/tests/CarDeveloperOptions/res/values-ta/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ta/strings.xml
@@ -648,7 +648,7 @@
     <string name="lock_last_password_attempt_before_wipe_profile" msgid="1535128774464384305">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால், உங்கள் பணி விவரமும் அதன் தரவும் நீக்கப்படும்"</string>
     <string name="lock_failed_attempts_now_wiping_device" msgid="8662360098784762828">"பலமுறை தவறாக முயன்றதால், சாதனத்தின் தரவு நீக்கப்படும்."</string>
     <string name="lock_failed_attempts_now_wiping_user" msgid="3793513796171561873">"பலமுறை தவறாக முயன்றதால், இந்தப் பயனர் நீக்கப்படுவார்."</string>
-    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"பலமுறை தவறாக முயன்றதால், இந்தப் பணி விவரமும் அதன் தரவும் நீக்கப்படும்."</string>
+    <string name="lock_failed_attempts_now_wiping_profile" msgid="5347108525299038285">"பலமுறை தவறாக முயன்றதால், இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்"</string>
     <string name="lock_failed_attempts_now_wiping_dialog_dismiss" msgid="3950582268749037318">"நிராகரி"</string>
     <plurals name="lockpassword_password_too_short" formatted="false" msgid="694091983183310827">
       <item quantity="other">குறைந்தது <xliff:g id="COUNT_1">%d</xliff:g> எழுத்துகள் இருக்க வேண்டும்</item>
@@ -1736,7 +1736,7 @@
     <string name="lockpassword_strong_auth_required_device_pin" msgid="24030584350601016">"கூடுதல் பாதுகாப்பிற்கு, சாதனப் பின்னை உள்ளிடவும்"</string>
     <string name="lockpassword_strong_auth_required_device_password" msgid="7746588206458754598">"கூடுதல் பாதுகாப்பிற்கு, சாதனக் கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="lockpassword_strong_auth_required_work_pattern" msgid="6861154706098327320">"கூடுதல் பாதுகாப்பிற்கு, பணிப் பேட்டர்னை வரையவும்"</string>
-    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"கூடுதல் பாதுகாப்பிற்கு, பணிப் பின்னை உள்ளிடவும்"</string>
+    <string name="lockpassword_strong_auth_required_work_pin" msgid="6306902249365524526">"கூடுதல் பாதுகாப்பிற்கு, பணிக்கான பின்னை உள்ளிடவும்"</string>
     <string name="lockpassword_strong_auth_required_work_password" msgid="2917338218971012776">"கூடுதல் பாதுகாப்பிற்கு, பணிக் கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="lockpassword_confirm_your_pattern_details_frp" msgid="1085862410379709928">"ஆரம்பநிலை அமைப்புகளுக்கு மீட்டமைக்கப்பட்டது. மொபைலைப் பயன்படுத்த, முந்தைய பேட்டர்னை உள்ளிடவும்."</string>
     <string name="lockpassword_confirm_your_pin_details_frp" msgid="6849889353126558761">"ஆரம்பநிலை அமைப்புகளுக்கு மீட்டமைக்கப்பட்டது. மொபைலைப் பயன்படுத்த, முந்தைய பின்னை உள்ளிடவும்."</string>
diff --git a/tests/CarDeveloperOptions/res/values-th/strings.xml b/tests/CarDeveloperOptions/res/values-th/strings.xml
index c5a725b..a247bb8 100644
--- a/tests/CarDeveloperOptions/res/values-th/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-th/strings.xml
@@ -3435,9 +3435,9 @@
     <string name="notification_channel_sound_title" msgid="7635366839003304745">"เสียง"</string>
     <string name="zen_mode_rule_delete_button" msgid="6763486487220471193">"ลบ"</string>
     <string name="zen_mode_rule_rename_button" msgid="1428130397306726792">"เปลี่ยนชื่อ"</string>
-    <string name="zen_mode_rule_name" msgid="8583652780885724670">"ชื่อกำหนดเวลา"</string>
+    <string name="zen_mode_rule_name" msgid="8583652780885724670">"ชื่อกำหนดการ"</string>
     <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"ระบุชื่อกำหนดการ"</string>
-    <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"มีการใช้ชื่อกำหนดเวลานี้แล้ว"</string>
+    <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"มีการใช้ชื่อกำหนดการนี้แล้ว"</string>
     <string name="zen_mode_add_rule" msgid="7200004557856029928">"เพิ่มอีก"</string>
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"เพิ่มกำหนดการตามกิจกรรม"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"เพิ่มกำหนดการตามเวลา"</string>
@@ -3469,10 +3469,10 @@
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"ไม่มี"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"ทุกวัน"</string>
     <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"เวลาปลุกจะแทนที่เวลาสิ้นสุดได้"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"กำหนดเวลาจะปิดเมื่อนาฬิกาปลุกดังขึ้น"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"กำหนดการจะปิดเมื่อนาฬิกาปลุกดังขึ้น"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"ลักษณะการทำงานของโหมดห้ามรบกวน"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"ใช้การตั้งค่าเริ่มต้น"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"สร้างการตั้งค่าที่กำหนดเองสำหรับกำหนดเวลานี้"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"สร้างการตั้งค่าที่กำหนดเองสำหรับกำหนดการนี้"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"สำหรับ \"<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>\""</string>
     <string name="summary_divider_text" msgid="4780683204694442666">", "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-vi/strings.xml b/tests/CarDeveloperOptions/res/values-vi/strings.xml
index 1efea2d..fbf1686 100644
--- a/tests/CarDeveloperOptions/res/values-vi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-vi/strings.xml
@@ -29,7 +29,7 @@
     <string name="show_dev_on" msgid="9075712234786224065">"Bạn đã là nhà phát triển!"</string>
     <string name="show_dev_already" msgid="7665948832405148689">"Không cần, bạn đã là nhà phát triển."</string>
     <string name="dev_settings_disabled_warning" msgid="3198732189395396721">"Vui lòng bật tùy chọn của nhà phát triển trước."</string>
-    <string name="header_category_wireless_networks" msgid="8968405993937795898">"Mạng không dây và mạng"</string>
+    <string name="header_category_wireless_networks" msgid="8968405993937795898">"Không dây và mạng"</string>
     <string name="header_category_system" msgid="4045988717359334410">"Hệ thống"</string>
     <string name="radio_info_data_connection_enable" msgid="2554249462719717119">"Bật kết nối dữ liệu"</string>
     <string name="radio_info_data_connection_disable" msgid="2430609627397999371">"Tắt kết nối dữ liệu"</string>
@@ -301,7 +301,7 @@
     <string name="settings_label_launcher" msgid="500627679902923496">"Cài đặt"</string>
     <string name="settings_shortcut" msgid="4503714880251502167">"Lối tắt cài đặt"</string>
     <string name="airplane_mode" msgid="4508870277398231073">"Chế độ trên máy bay"</string>
-    <string name="wireless_networks_settings_title" msgid="4298430520189173949">"Không dây &amp; mạng"</string>
+    <string name="wireless_networks_settings_title" msgid="4298430520189173949">"Không dây và mạng"</string>
     <string name="radio_controls_summary" msgid="4596981962167684814">"Quản lý Wi-Fi, Bluetooth, chế độ trên máy bay, mạng di động và VPN"</string>
     <string name="cellular_data_title" msgid="7909624119432695022">"Dữ liệu di động"</string>
     <string name="calls_title" msgid="875693497825736550">"Cho phép cuộc gọi"</string>
@@ -1826,7 +1826,7 @@
     <string name="disable_text" msgid="5065834603951474397">"Tắt"</string>
     <string name="enable_text" msgid="7179141636849225884">"Bật"</string>
     <string name="clear_user_data_text" msgid="8894073247302821764">"Xóa bộ nhớ"</string>
-    <string name="app_factory_reset" msgid="8718986000278776272">"Gỡ cài đặt cập nhật"</string>
+    <string name="app_factory_reset" msgid="8718986000278776272">"Gỡ cài đặt bản cập nhật"</string>
     <string name="auto_launch_enable_text" msgid="3372898942144027341">"Bạn đã chọn chạy ứng dụng này theo mặc định cho một số tác vụ."</string>
     <string name="always_allow_bind_appwidgets_text" msgid="2286211654774611037">"Bạn đã chọn cho phép ứng dụng này tạo các tiện ích và truy cập dữ liệu của chúng."</string>
     <string name="auto_launch_disable_text" msgid="8560921288036801416">"Chưa đặt mặc định."</string>
@@ -3468,9 +3468,9 @@
     <string name="zen_mode_schedule_rule_days" msgid="220627703673691816">"Ngày"</string>
     <string name="zen_mode_schedule_rule_days_none" msgid="6011716195119389956">"Không có"</string>
     <string name="zen_mode_schedule_rule_days_all" msgid="8814173364016139675">"Hàng ngày"</string>
-    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Báo thức có thể ghi đè thời gian kết thúc"</string>
-    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Lịch biểu tắt khi lịch báo thức đổ chuông"</string>
-    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Hành vi Không làm phiền"</string>
+    <string name="zen_mode_schedule_alarm_title" msgid="2078194049274875023">"Đồng hồ báo thức có thể vô hiệu hóa thời gian kết thúc"</string>
+    <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"Lịch biểu tắt khi một đồng hồ báo thức đổ chuông"</string>
+    <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"Hoạt động ở chế độ Không làm phiền"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"Sử dụng các tùy chọn cài đặt mặc định"</string>
     <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"Tạo các mục cài đặt tùy chỉnh cho lịch biểu này"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"Dành cho ‘<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>’"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
index 5e42e3c..91a5f32 100644
--- a/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zh-rHK/strings.xml
@@ -3178,17 +3178,17 @@
     <string name="zen_mode_behavior_total_silence" msgid="371498357539257671">"完全靜音"</string>
     <string name="zen_mode_behavior_no_sound_except" msgid="8894465423364103198">"不發出音效 (<xliff:g id="CATEGORIES">%1$s</xliff:g>除外)"</string>
     <string name="zen_mode_behavior_alarms_only" msgid="8406622989983047562">"不發出音效 (鬧鐘和媒體除外)"</string>
-    <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"預定時間"</string>
+    <string name="zen_mode_automation_settings_title" msgid="3916960043054489008">"時間表"</string>
     <string name="zen_mode_delete_automatic_rules" msgid="2455264581527305755">"刪除日程表"</string>
     <string name="zen_mode_schedule_delete" msgid="7786092652527516740">"刪除"</string>
     <string name="zen_mode_rule_name_edit" msgid="5479435215341745578">"編輯"</string>
-    <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"預定時間"</string>
+    <string name="zen_mode_automation_settings_page_title" msgid="3001783354881078983">"時間表"</string>
     <string name="zen_mode_automatic_rule_settings_page_title" msgid="5272888746413504692">"預定時間"</string>
     <string name="zen_mode_schedule_category_title" msgid="1936785755444711221">"預定時間"</string>
     <string name="zen_mode_automation_suggestion_title" msgid="4921779962633710347">"在特定時間將手機設為靜音"</string>
     <string name="zen_mode_automation_suggestion_summary" msgid="2709837472884371037">"設定「請勿騷擾」規則"</string>
     <string name="zen_mode_schedule_title" msgid="5275268813192802631">"預定時間"</string>
-    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"使用日程表"</string>
+    <string name="zen_mode_use_automatic_rule" msgid="446326253915861824">"使用時間表"</string>
     <string name="zen_mode_option_important_interruptions" msgid="5173944276846940149">"只限優先"</string>
     <string name="zen_mode_option_alarms" msgid="4843278125235203076">"只限鬧鐘"</string>
     <string name="zen_mode_option_no_interruptions" msgid="4723700274519260852">"完全靜音"</string>
@@ -3436,14 +3436,14 @@
     <string name="notification_channel_sound_title" msgid="7635366839003304745">"音效"</string>
     <string name="zen_mode_rule_delete_button" msgid="6763486487220471193">"刪除"</string>
     <string name="zen_mode_rule_rename_button" msgid="1428130397306726792">"重新命名"</string>
-    <string name="zen_mode_rule_name" msgid="8583652780885724670">"日程表名稱"</string>
+    <string name="zen_mode_rule_name" msgid="8583652780885724670">"時間表名稱"</string>
     <string name="zen_mode_rule_name_hint" msgid="6569877315858105901">"輸入日程表名稱"</string>
     <string name="zen_mode_rule_name_warning" msgid="4773465816059587512">"日程表名稱已使用"</string>
     <string name="zen_mode_add_rule" msgid="7200004557856029928">"加入更多"</string>
     <string name="zen_mode_add_event_rule" msgid="1398181272397489506">"加入日程表 (活動)"</string>
     <string name="zen_mode_add_time_rule" msgid="5999467757140524729">"加入日程表 (時間)"</string>
     <string name="zen_mode_delete_rule" msgid="2292933835997203801">"刪除日程表"</string>
-    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"選擇日程表類型"</string>
+    <string name="zen_mode_choose_rule_type" msgid="8877138307319450306">"選擇時間表類型"</string>
     <string name="zen_mode_delete_rule_confirmation" msgid="2646596466259025978">"要刪除規則「<xliff:g id="RULE">%1$s</xliff:g>」嗎?"</string>
     <string name="zen_mode_delete_rule_button" msgid="611058106279881991">"刪除"</string>
     <string name="zen_mode_rule_type_unknown" msgid="2819480113355191421">"未知"</string>
@@ -3473,7 +3473,7 @@
     <string name="zen_mode_schedule_alarm_summary" msgid="5556997989911412070">"鬧鐘響起時,系統會關閉日程表"</string>
     <string name="zen_mode_custom_behavior_title" msgid="8908861697886331001">"「請勿騷擾」行為"</string>
     <string name="zen_mode_custom_behavior_summary_default" msgid="3509865340195397447">"使用預設設定"</string>
-    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"為此日程表建立自訂設定"</string>
+    <string name="zen_mode_custom_behavior_summary" msgid="7206909852887332604">"為此時間表建立自訂設定"</string>
     <string name="zen_mode_custom_behavior_category_title" msgid="7451686525113262087">"時段:「<xliff:g id="SCHEDULE_NAME">%1$s</xliff:g>」"</string>
     <string name="summary_divider_text" msgid="4780683204694442666">"、 "</string>
     <string name="summary_range_symbol_combination" msgid="6038631664844488406">"<xliff:g id="START">%1$s</xliff:g> - <xliff:g id="END">%2$s</xliff:g>"</string>
diff --git a/tests/CarDeveloperOptions/res/values-zu/strings.xml b/tests/CarDeveloperOptions/res/values-zu/strings.xml
index e5a7c0e..febfd3c 100644
--- a/tests/CarDeveloperOptions/res/values-zu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-zu/strings.xml
@@ -3307,7 +3307,7 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"Fihla izithonjana ezithulile zesimo sokwazisa"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Fihla izithonjana zezaziso ezithulile kubha yesimo"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"Vumela amachashazi esaziso"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"Amabhamu"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"Amabhamuza"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Finyelela ngokushesha okuqukethwe kohlelo lokusebenza kusuka noma yikuphi usebenzisa izinqamuleli ezintantayo"</string>
     <string name="bubbles_feature_education" msgid="8979109826818881018">"Ezinye izaziso nokunye okuqukethwe kungavela njengamabhamuza kusikrini. Ukuze uvule ibhamuza, lithephe. Ukuze ulicashise, lidonsele phansi kusikrini."</string>
     <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Amabhamuza"</string>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio_input.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input.xml
new file mode 100644
index 0000000..3e2dd0c
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 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.
+  -->
+<LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/zones_input_tab"
+        android:layout_width="match_parent"
+        android:layout_height="50dp">
+    </com.google.android.material.tabs.TabLayout>
+    <androidx.viewpager.widget.ViewPager
+        android:id="@+id/zones_input_view_pager"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+    </androidx.viewpager.widget.ViewPager>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/audio_input_item.xml b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input_item.xml
new file mode 100644
index 0000000..ac87a74
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/audio_input_item.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:id="@+id/input_device_address"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="20sp"
+        android:layout_weight="1">
+    </TextView>
+    <Button
+        android:id="@+id/play_audio_input"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="20dp"
+        android:text="@string/play_audio_input" />
+    <Button
+        android:id="@+id/stop_audio_input"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/stop_audio_input"/>
+    <TextView
+        android:id="@+id/input_device_state"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:textSize="20sp"
+        android:layout_weight="1"
+        android:text="@string/player_not_started">
+    </TextView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/zone_input_tab.xml b/tests/EmbeddedKitchenSinkApp/res/layout/zone_input_tab.xml
new file mode 100644
index 0000000..f552265
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/zone_input_tab.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ListView
+        android:id="@+id/input_list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="3">
+    </ListView>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 162c37d..e64c094 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -118,6 +118,7 @@
     <string name="player_paused" translatable="false">Player Paused</string>
     <string name="player_started" translatable="false">Player Started</string>
     <string name="player_delayed" translatable="false">Player Delayed</string>
+    <string name="player_stopped" translatable="false">Player Stopped</string>
     <string name="nav_play" translatable="false">Nav Play</string>
     <string name="vr_play" translatable="false">VR Play</string>
     <string name="system_play" translatable="false">System Play</string>
@@ -142,6 +143,10 @@
     <string name="no_zone" translatable="false">none</string>
     <string name="phone_audio_player" translatable="false">Phone Player</string>
 
+    <!-- Audio Input-->
+    <string name="play_audio_input" translatable="false">Play</string>
+    <string name="stop_audio_input" translatable="false">Stop</string>
+
     <!-- keyboard test fragment -->
     <string name="keyboard_test_title" translatable="false">Keyboard Test</string>
     <string name="on_search" translatable="false">OnSearch:</string>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index d210971..20dd9fc 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -45,6 +45,7 @@
 import com.google.android.car.kitchensink.alertdialog.AlertDialogTestFragment;
 import com.google.android.car.kitchensink.assistant.CarAssistantFragment;
 import com.google.android.car.kitchensink.audio.AudioTestFragment;
+import com.google.android.car.kitchensink.audio.CarAudioInputTestFragment;
 import com.google.android.car.kitchensink.bluetooth.BluetoothHeadsetFragment;
 import com.google.android.car.kitchensink.bluetooth.MapMceTestFragment;
 import com.google.android.car.kitchensink.carboard.KeyboardTestFragment;
@@ -167,6 +168,7 @@
             new FragmentMenuEntry("alert window", AlertDialogTestFragment.class),
             new FragmentMenuEntry("assistant", CarAssistantFragment.class),
             new FragmentMenuEntry("audio", AudioTestFragment.class),
+            new FragmentMenuEntry("Audio Input", CarAudioInputTestFragment.class),
             new FragmentMenuEntry("BT headset", BluetoothHeadsetFragment.class),
             new FragmentMenuEntry("BT messaging", MapMceTestFragment.class),
             new FragmentMenuEntry("carapi", CarApiTestFragment.class),
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputAdapter.java
new file mode 100644
index 0000000..fd680fd
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 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 com.google.android.car.kitchensink.audio;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.android.car.kitchensink.R;
+
+public final class CarAudioInputAdapter
+        extends ArrayAdapter<CarAudioZoneInputFragment.CarAudioAudioInputInfo> {
+
+    private static final String TAG = "AUDIO.INPUT."
+            + CarAudioInputAdapter.class.getSimpleName();
+    private static final boolean DEBUG = true;
+    private final Context mContext;
+    private CarAudioZoneInputFragment.CarAudioAudioInputInfo[] mAudioDeviceInfos;
+    private final int mLayoutResourceId;
+    private CarAudioZoneInputFragment mFragment;
+
+    public CarAudioInputAdapter(Context context,
+            int layoutResourceId, CarAudioZoneInputFragment.CarAudioAudioInputInfo[]
+            carInputDevicesInfos, CarAudioZoneInputFragment fragment) {
+        super(context, layoutResourceId, carInputDevicesInfos);
+        mFragment = fragment;
+        mContext = context;
+        mLayoutResourceId = layoutResourceId;
+        mAudioDeviceInfos = carInputDevicesInfos;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (DEBUG) {
+            Log.d(TAG, "getView position " + position);
+        }
+        ViewHolder vh = new ViewHolder();
+        if (convertView == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            convertView = inflater.inflate(mLayoutResourceId, parent, false);
+            vh.mDeviceAddress = convertView.findViewById(R.id.input_device_address);
+            vh.mPlayButton = convertView.findViewById(R.id.play_audio_input);
+            vh.mStopButton = convertView.findViewById(R.id.stop_audio_input);
+            vh.mPlayerState = convertView.findViewById(R.id.input_device_state);
+            convertView.setTag(vh);
+        } else {
+            vh = (ViewHolder) convertView.getTag();
+        }
+        if (mAudioDeviceInfos[position] != null) {
+            String deviceAddress = mAudioDeviceInfos[position].mDeviceAddress;
+            vh.mDeviceAddress.setText(deviceAddress);
+            if (position == 0) {
+                vh.mPlayButton.setVisibility(View.INVISIBLE);
+                vh.mStopButton.setVisibility(View.INVISIBLE);
+                vh.mPlayerState.setVisibility(View.INVISIBLE);
+            } else {
+                vh.mPlayButton.setVisibility(View.VISIBLE);
+                vh.mPlayButton.setOnClickListener((View v) -> playAudio(mAudioDeviceInfos[position]
+                        .mDeviceAddress));
+                vh.mStopButton.setVisibility(View.VISIBLE);
+                vh.mStopButton.setOnClickListener((View v) -> stopAudio(mAudioDeviceInfos[position]
+                        .mDeviceAddress));
+                vh.mPlayerState.setVisibility(View.VISIBLE);
+                vh.mPlayerState.setText(getPlayerStateStringResource(mAudioDeviceInfos[position]
+                        .mPlayerState));
+            }
+        }
+        return convertView;
+    }
+
+    private void playAudio(String deviceAddress) {
+        mFragment.playAudio(deviceAddress);
+    }
+
+    private void stopAudio(String deviceAddress) {
+        mFragment.stopAudio(deviceAddress);
+    }
+
+    private int getPlayerStateStringResource(int state) {
+        switch (state) {
+            case CarAudioZoneInputFragment.PLAYING_STATE:
+                return R.string.player_started;
+            case CarAudioZoneInputFragment.PAUSED_STATE:
+                return R.string.player_paused;
+            case CarAudioZoneInputFragment.DELAYED_STATE:
+                return R.string.player_delayed;
+            case CarAudioZoneInputFragment.STOPPED_STATE:
+            default:
+                return R.string.player_stopped;
+        }
+    }
+
+    @Override
+    public int getCount() {
+        return mAudioDeviceInfos.length;
+    }
+
+    public void refreshAudioInputs(CarAudioZoneInputFragment.CarAudioAudioInputInfo[]
+            carInputDevicesInfos) {
+        mAudioDeviceInfos = carInputDevicesInfos;
+    }
+
+    private static final class ViewHolder {
+        public TextView mDeviceAddress;
+        public Button mPlayButton;
+        public Button mStopButton;
+        public TextView mPlayerState;
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java
new file mode 100644
index 0000000..0382cf6
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioInputTestFragment.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 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 com.google.android.car.kitchensink.audio;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.Car;
+import android.car.media.CarAudioManager;
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.car.kitchensink.R;
+import com.google.android.material.tabs.TabLayout;
+
+import java.util.List;
+
+public class CarAudioInputTestFragment extends Fragment {
+    private static final String TAG = "CAR.AUDIO.INPUT.KS";
+    private static final boolean DEBUG = true;
+
+
+    private Handler mHandler;
+    private Context mContext;
+
+    private Car mCar;
+    private AudioManager mAudioManager;
+    private CarAudioManager mCarAudioManager;
+    private TabLayout mZonesTabLayout;
+    private CarAudioZoneInputTabAdapter mInputAudioZoneAdapter;
+    private ViewPager mViewPager;
+
+    private void connectCar() {
+        mContext = getContext();
+        mHandler = new Handler(Looper.getMainLooper());
+        mCar = Car.createCar(mContext, /* handler= */ null,
+                Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
+    }
+
+    private Car.CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
+            if (DEBUG) {
+                Log.d(TAG, "Disconnect from Car Service");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Connected to Car Service");
+        }
+        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+
+        mAudioManager = mContext.getSystemService(AudioManager.class);
+    };
+
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+        Log.i(TAG, "onCreateView");
+        View view = inflater.inflate(R.layout.audio_input, container, false);
+        connectCar();
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        Log.i(TAG, "onViewCreated ");
+        mZonesTabLayout = view.findViewById(R.id.zones_input_tab);
+        mViewPager = (ViewPager) view.findViewById(R.id.zones_input_view_pager);
+
+        mInputAudioZoneAdapter = new CarAudioZoneInputTabAdapter(getChildFragmentManager());
+        mViewPager.setAdapter(mInputAudioZoneAdapter);
+        initInputInfo();
+        mZonesTabLayout.setupWithViewPager(mViewPager);
+    }
+
+    @Override
+    public void onDestroyView() {
+        Log.i(TAG, "onDestroyView");
+
+        if (mCar != null && mCar.isConnected()) {
+            mCar.disconnect();
+            mCar = null;
+        }
+        super.onDestroyView();
+    }
+
+    private void initInputInfo() {
+        if (!mCarAudioManager.isDynamicRoutingEnabled()) {
+            return;
+        }
+        List<Integer> audioZoneList = mCarAudioManager.getAudioZoneIds();
+        for (int audioZoneId : audioZoneList) {
+            if (mCarAudioManager.getInputDevicesForZoneId(audioZoneId).isEmpty()) {
+                if (DEBUG) {
+                    Log.d(TAG, "Audio Zone " + audioZoneId + " has no input devices");
+                }
+                continue;
+            }
+            addAudioZoneInputDevices(audioZoneId);
+        }
+        mInputAudioZoneAdapter.notifyDataSetChanged();
+    }
+
+    private void addAudioZoneInputDevices(int audioZoneId) {
+        String title = "Audio Zone " + audioZoneId;
+        if (DEBUG) {
+            Log.d(TAG, title + " adding devices");
+        }
+        CarAudioZoneInputFragment fragment = new CarAudioZoneInputFragment(audioZoneId,
+                mCarAudioManager, mAudioManager);
+
+        mZonesTabLayout.addTab(mZonesTabLayout.newTab().setText(title));
+        mInputAudioZoneAdapter.addFragment(fragment, title);
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputFragment.java
new file mode 100644
index 0000000..9f2910f
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputFragment.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 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 com.google.android.car.kitchensink.audio;
+
+import android.car.media.CarAudioManager;
+import android.car.media.CarAudioPatchHandle;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFocusRequest;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.annotation.concurrent.GuardedBy;
+
+public final class CarAudioZoneInputFragment extends Fragment {
+    private static final String TAG = "CAR.AUDIO.INPUT."
+            + CarAudioZoneInputFragment.class.getSimpleName();
+    private static final boolean DEBUG = true;
+
+    static final int PLAYING_STATE = 0;
+    static final int PAUSED_STATE = 1;
+    static final int STOPPED_STATE = 2;
+    static final int DELAYED_STATE = 3;
+
+    private final Object mLock = new Object();
+    private final int mAudioZoneId;
+    private final CarAudioManager mCarAudioManager;
+    private final AudioManager mAudioManager;
+    @GuardedBy("mLock")
+    private final Map<String, CarAudioAudioInputInfo> mAudioDeviceInfoMap = new HashMap<>();
+    @GuardedBy("mLock")
+    private String mActiveInputAddress;
+    @GuardedBy("mLock")
+    private CarAudioPatchHandle mAudioPatch;
+    @GuardedBy("mLock")
+    private AudioFocusRequest mAudioFocusRequest;
+    @GuardedBy("mLock")
+    private InputAudioFocusListener mAudioFocusListener;
+
+    private CarAudioInputAdapter mCarAudioInputAdapter;
+    private CarAudioAudioInputInfo[] mCarInputDevicesInfos = new CarAudioAudioInputInfo[0];
+    private final AudioAttributes mAudioAttributes;
+
+    public CarAudioZoneInputFragment(int audioZoneId, CarAudioManager carAudioManager,
+            AudioManager audioManager) {
+        mAudioZoneId = audioZoneId;
+        mCarAudioManager = carAudioManager;
+        mAudioManager = audioManager;
+        mAudioAttributes = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_MEDIA)
+                .build();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        if (DEBUG) {
+            Log.d(TAG, "onCreateView " + mAudioZoneId);
+        }
+        View view = inflater.inflate(R.layout.zone_input_tab, container, false);
+        ListView audiInputListView = view.findViewById(R.id.input_list);
+        mCarAudioInputAdapter =
+                new CarAudioInputAdapter(getContext(), R.layout.audio_input_item,
+                        mCarInputDevicesInfos, this);
+        initAudioInputInfo(mAudioZoneId);
+        audiInputListView.setAdapter(mCarAudioInputAdapter);
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        synchronized (mLock) {
+            if (mActiveInputAddress != null) {
+                stopAudio(mActiveInputAddress);
+            }
+        }
+        super.onDestroyView();
+    }
+
+    void initAudioInputInfo(int audioZoneId) {
+        List<AudioDeviceInfo> inputDevices =
+                mCarAudioManager.getInputDevicesForZoneId(audioZoneId);
+        mCarInputDevicesInfos = new CarAudioAudioInputInfo[inputDevices.size() + 1];
+        CarAudioAudioInputInfo titlesInfo = new CarAudioAudioInputInfo();
+        titlesInfo.mDeviceAddress = "Device Address";
+        titlesInfo.mPlayerState = STOPPED_STATE;
+        mCarInputDevicesInfos[0] = titlesInfo;
+
+        synchronized (mLock) {
+            for (int index = 0; index < inputDevices.size(); index++) {
+                AudioDeviceInfo info = inputDevices.get(index);
+                CarAudioAudioInputInfo audioInput = new CarAudioAudioInputInfo();
+                audioInput.mCarAudioZone = mAudioZoneId;
+                audioInput.mDeviceAddress = info.getAddress();
+                audioInput.mPlayerState = STOPPED_STATE;
+                mCarInputDevicesInfos[index + 1] = audioInput;
+
+                if (DEBUG) {
+                    Log.d(TAG, audioInput.toString());
+                }
+                mAudioDeviceInfoMap.put(info.getAddress(), audioInput);
+            }
+        }
+        mCarAudioInputAdapter.refreshAudioInputs(mCarInputDevicesInfos);
+    }
+
+    public void playAudio(@NonNull String deviceAddress) {
+        Objects.requireNonNull(deviceAddress);
+        synchronized (mLock) {
+            if (deviceAddress.equals(mActiveInputAddress)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Audio already playing");
+                }
+                return;
+            }
+            if (mActiveInputAddress != null) {
+                mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
+                stopAudioLocked();
+            }
+
+            mAudioFocusListener = new InputAudioFocusListener();
+            mAudioFocusRequest = new AudioFocusRequest
+                    .Builder(AudioManager.AUDIOFOCUS_GAIN)
+                    .setAudioAttributes(mAudioAttributes)
+                    .setOnAudioFocusChangeListener(mAudioFocusListener)
+                    .setForceDucking(false)
+                    .setWillPauseWhenDucked(false)
+                    .setAcceptsDelayedFocusGain(true)
+                    .build();
+
+            int audioFocusRequestResults = mAudioManager.requestAudioFocus(mAudioFocusRequest);
+            if (audioFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+                mActiveInputAddress = deviceAddress;
+                startAudioLocked();
+                return;
+            } else if (audioFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+                // Keep the device but will start the audio once we get the focus gain
+                mActiveInputAddress = deviceAddress;
+                mAudioDeviceInfoMap.get(deviceAddress).mPlayerState = DELAYED_STATE;
+                mCarAudioInputAdapter.notifyDataSetChanged();
+                return;
+            }
+
+            // Focus was rejected
+            mAudioFocusRequest = null;
+            mAudioFocusListener = null;
+        }
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    public void stopAudio(@NonNull String deviceAddress) {
+        Objects.requireNonNull(deviceAddress);
+        synchronized (mLock) {
+            if (deviceAddress.equals(mActiveInputAddress)) {
+                mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
+                stopAudioLocked();
+            }
+        }
+    }
+
+    private void startAudioLocked() {
+        if (mAudioPatch != null) {
+            if (DEBUG) {
+                Log.d(TAG, "Audio already playing");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Starting audio input " + mActiveInputAddress);
+        }
+        mAudioPatch = mCarAudioManager.createAudioPatch(mActiveInputAddress,
+                AudioAttributes.USAGE_MEDIA, 0);
+        mAudioDeviceInfoMap.get(mActiveInputAddress).mPlayerState = PLAYING_STATE;
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    private void pauseAudioLocked() {
+        if (mAudioPatch == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Audio already paused");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Pausing audio input " + mActiveInputAddress);
+        }
+        mCarAudioManager.releaseAudioPatch(mAudioPatch);
+        mAudioPatch = null;
+        mAudioDeviceInfoMap.get(mActiveInputAddress).mPlayerState = PAUSED_STATE;
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    private void stopAudioLocked() {
+        if (mAudioPatch == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Audio already stopped");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Stopping audio input " + mActiveInputAddress);
+        }
+        mCarAudioManager.releaseAudioPatch(mAudioPatch);
+        mAudioDeviceInfoMap.get(mActiveInputAddress).mPlayerState = STOPPED_STATE;
+        mAudioPatch = null;
+        mAudioFocusRequest = null;
+        mAudioFocusListener = null;
+        mActiveInputAddress = null;
+
+        mCarAudioInputAdapter.notifyDataSetChanged();
+    }
+
+    private final class InputAudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
+
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            if (DEBUG) {
+                Log.d(TAG, "InputAudioFocusListener focus change:" + focusChange);
+            }
+            synchronized (mLock) {
+                switch (focusChange) {
+                    case AudioManager.AUDIOFOCUS_GAIN:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+                    case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                        startAudioLocked();
+                        break;
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                        pauseAudioLocked();
+                        break;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                    default:
+                        stopAudioLocked();
+                        break;
+                }
+            }
+        }
+    }
+
+    public static class CarAudioAudioInputInfo {
+        public int mCarAudioZone;
+        public String mDeviceAddress;
+        public int mPlayerState;
+
+        @Override
+        public String toString() {
+            return "Device address " + mDeviceAddress + ", Audio zone id " + mCarAudioZone;
+        }
+    }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputTabAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputTabAdapter.java
new file mode 100644
index 0000000..65ec312
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/audio/CarAudioZoneInputTabAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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 com.google.android.car.kitchensink.audio;
+
+import android.os.Parcelable;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class CarAudioZoneInputTabAdapter extends FragmentStatePagerAdapter {
+
+    private static final String TAG = "CAR.AUDIO.INPUT."
+            + CarAudioZoneInputTabAdapter.class.getSimpleName();
+    private final List<Fragment> mFragmentList = new ArrayList<>();
+    private final List<String> mFragmentTitleList = new ArrayList<>();
+    CarAudioZoneInputTabAdapter(FragmentManager fm) {
+        super(fm);
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return mFragmentList.get(position);
+    }
+
+    public void addFragment(Fragment fragment, String title) {
+        mFragmentList.add(fragment);
+        mFragmentTitleList.add(title);
+    }
+
+    @Nullable
+    @Override
+    public CharSequence getPageTitle(int position) {
+        return mFragmentTitleList.get(position);
+    }
+
+    @Override
+    public int getCount() {
+        return mFragmentList.size();
+    }
+
+    @Override
+    public Parcelable saveState() {
+        return null;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index ee5c311..4580e59 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -589,7 +589,7 @@
                 .thenReturn(false);
         mCarUserService.switchDriver(mAdminUser.id, mUserSwitchFuture);
         assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_ALREADY_REQUESTED_USER);
+                .isEqualTo(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
     }
 
     @Test
@@ -792,7 +792,7 @@
         mCarUserService.switchUser(mAdminUser.id, mAsyncCallTimeoutMs, mUserSwitchFuture);
 
         assertThat(getUserSwitchResult().getStatus())
-                .isEqualTo(UserSwitchResult.STATUS_ALREADY_REQUESTED_USER);
+                .isEqualTo(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND);
     }
 
     @Test
diff --git a/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java b/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java
index 385bb4e..41d37ef 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/UserSwitchResultTest.java
@@ -50,7 +50,7 @@
     @Test
     public void testIUserSwitchResult_isSuccess_requestedState() {
         UserSwitchResult result =
-                new UserSwitchResult(UserSwitchResult.STATUS_ALREADY_REQUESTED_USER, null);
+                new UserSwitchResult(UserSwitchResult.STATUS_OK_USER_ALREADY_IN_FOREGROUND, null);
         assertThat(result.isSuccess()).isTrue();
     }
 }