Merge "Update Bluetooth Profile defaults only while bonding." into rvc-dev
diff --git a/FrameworkPackageStubs/AndroidManifest.xml b/FrameworkPackageStubs/AndroidManifest.xml
index 6c25bcd..ac674cb 100644
--- a/FrameworkPackageStubs/AndroidManifest.xml
+++ b/FrameworkPackageStubs/AndroidManifest.xml
@@ -194,5 +194,30 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+        <!-- Contacts package stubs -->
+        <activity
+            android:name=".Stubs$ContactsStub"
+            android:label="@string/stub_name"
+            android:excludeFromRecents="true">
+            <intent-filter android:priority="-1">
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/contact"/>
+            </intent-filter>
+
+            <intent-filter android:priority="-1">
+                <action android:name="android.intent.action.GET_CONTENT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/contact"/>
+            </intent-filter>
+
+            <intent-filter android:priority="-1">
+                <action android:name="android.intent.action.PICK" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/contact"/>
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/car-lib/src/android/car/media/CarAudioPatchHandle.java b/car-lib/src/android/car/media/CarAudioPatchHandle.java
index 20fbab0..8bc4cfe 100644
--- a/car-lib/src/android/car/media/CarAudioPatchHandle.java
+++ b/car-lib/src/android/car/media/CarAudioPatchHandle.java
@@ -70,9 +70,7 @@
      * @hide
      */
     public boolean represents(AudioPatch patch) {
-        return patch.sources().length == 1
-                && patch.sinks().length == 1
-                && patch.id() == mHandleId;
+        return patch.id() == mHandleId;
     }
 
     @Override
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..1cd28e9 100644
--- a/car-lib/src/android/car/user/CarUserManager.java
+++ b/car-lib/src/android/car/user/CarUserManager.java
@@ -40,6 +40,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.sysprop.CarProperties;
 import android.util.ArrayMap;
 import android.util.EventLog;
@@ -207,6 +208,11 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public AndroidFuture<UserSwitchResult> switchUser(@UserIdInt int targetUserId) {
         int uid = myUid();
+
+        if (mUserManager.getUserSwitchability() != UserManager.SWITCHABILITY_STATUS_OK) {
+            return newSwitchResuiltForFailure(UserSwitchResult.STATUS_NOT_SWITCHABLE);
+        }
+
         try {
             AndroidFuture<UserSwitchResult> future = new AndroidFuture<UserSwitchResult>() {
                 @Override
@@ -218,19 +224,25 @@
                         Log.w(TAG, "switchUser(" + targetUserId + ") failed: " + err);
                     }
                     super.onCompleted(result, err);
-                };
+                }
             };
             EventLog.writeEvent(EventLogTags.CAR_USER_MGR_SWITCH_USER_REQ, uid, targetUserId);
             mService.switchUser(targetUserId, HAL_TIMEOUT_MS, future);
             return future;
         } catch (RemoteException e) {
-            AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
-            future.complete(
-                    new UserSwitchResult(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE, null));
+            AndroidFuture<UserSwitchResult> future =
+                    newSwitchResuiltForFailure(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE);
             return handleRemoteExceptionFromCarService(e, future);
         }
     }
 
+    private AndroidFuture<UserSwitchResult> newSwitchResuiltForFailure(
+            @UserSwitchResult.Status int status) {
+        AndroidFuture<UserSwitchResult> future = new AndroidFuture<>();
+        future.complete(new UserSwitchResult(status, null));
+        return future;
+    }
+
     /**
      * Creates a new Android user.
      *
@@ -248,6 +260,10 @@
                     if (result != null) {
                         EventLog.writeEvent(EventLogTags.CAR_USER_MGR_CREATE_USER_RESP, uid,
                                 result.getStatus(), result.getErrorMessage());
+                        UserInfo user = result.getUser();
+                        if (result.isSuccess() && user != null && user.isGuest()) {
+                            onGuestCreated(user);
+                        }
                     } else {
                         Log.w(TAG, "createUser(" + userType + "," + UserInfo.flagsToString(flags)
                                 + ") failed: " + err);
@@ -267,6 +283,35 @@
         }
     }
 
+    /**
+     * Creates a new guest Android user.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    public AndroidFuture<UserCreationResult> createGuest(@Nullable String name) {
+        return createUser(name, UserManager.USER_TYPE_FULL_GUEST, /* flags= */ 0);
+    }
+
+    /**
+     * Creates a new Android user.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS})
+    public AndroidFuture<UserCreationResult> createUser(@Nullable String name,
+            @UserInfoFlag int flags) {
+        return createUser(name, UserManager.USER_TYPE_FULL_SECONDARY, flags);
+    }
+
+    // TODO(b/159283854): move to UserManager
+    private void onGuestCreated(UserInfo user) {
+        Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                Settings.Secure.SKIP_FIRST_USE_HINTS, "1", user.id);
+    }
+
      /**
      * Removes a user.
      *
@@ -404,8 +449,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) {
@@ -603,6 +649,12 @@
 
     // TODO(b/150413515): use from UserHelper instead (would require a new make target, otherwise it
     // would include the whole car-user-lib)
+    private boolean isHeadlessSystemUser(int targetUserId) {
+        return targetUserId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode();
+    }
+
+    // TODO(b/150413515): use from UserHelper instead (would require a new make target, otherwise it
+    // would include the whole car-user-lib)
     @Nullable
     private static String safeName(@Nullable String name) {
         return name == null ? name : name.length() + "_chars";
diff --git a/car-lib/src/android/car/user/UserSwitchResult.java b/car-lib/src/android/car/user/UserSwitchResult.java
index 55e2dbc..5c1ca23 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;
 
     /**
@@ -84,16 +84,23 @@
             CommonResults.LAST_COMMON_STATUS + 3;
 
     /**
+     * When switching users is currently not allowed for the user this process is running under.
+     */
+    public static final int STATUS_NOT_SWITCHABLE =
+            CommonResults.LAST_COMMON_STATUS + 4;
+
+    /**
      * Gets the user switch result status.
      *
      * @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
      *         {@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_INVALID_REQUEST},
+     *         {@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}.
+     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
      */
     private final @Status int mStatus;
 
@@ -107,7 +114,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,10 +140,11 @@
         STATUS_ANDROID_FAILURE,
         STATUS_HAL_FAILURE,
         STATUS_HAL_INTERNAL_FAILURE,
-        STATUS_ALREADY_REQUESTED_USER,
+        STATUS_INVALID_REQUEST,
+        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
+        STATUS_NOT_SWITCHABLE
     })
     @Retention(RetentionPolicy.SOURCE)
     @DataClass.Generated.Member
@@ -154,14 +162,16 @@
                     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_INVALID_REQUEST:
+                    return "STATUS_INVALID_REQUEST";
+            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:
                     return "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST";
-            case STATUS_INVALID_REQUEST:
-                    return "STATUS_INVALID_REQUEST";
+            case STATUS_NOT_SWITCHABLE:
+                    return "STATUS_NOT_SWITCHABLE";
             default: return Integer.toHexString(value);
         }
     }
@@ -176,19 +186,43 @@
      *           {@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_INVALID_REQUEST},
+     *           {@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}.
+     *           {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
      * @param errorMessage
      *   Gets the error message, if any.
      * @hide
      */
     @DataClass.Generated.Member
     public UserSwitchResult(
-            int status,
+            @Status int status,
             @Nullable String errorMessage) {
         this.mStatus = status;
+
+        if (!(mStatus == STATUS_SUCCESSFUL)
+                && !(mStatus == STATUS_ANDROID_FAILURE)
+                && !(mStatus == STATUS_HAL_FAILURE)
+                && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+                && !(mStatus == STATUS_INVALID_REQUEST)
+                && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
+                && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
+                && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
+                && !(mStatus == STATUS_NOT_SWITCHABLE)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+                            + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+                            + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+                            + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+                            + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + "), "
+                            + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
+                            + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
+                            + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
+                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + ")");
+        }
+
         this.mErrorMessage = errorMessage;
 
         // onConstructed(); // You can define this method to get a callback
@@ -201,13 +235,14 @@
      *         {@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_INVALID_REQUEST},
+     *         {@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}.
+     *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}.
      */
     @DataClass.Generated.Member
-    public int getStatus() {
+    public @Status int getStatus() {
         return mStatus;
     }
 
@@ -226,7 +261,7 @@
         // String fieldNameToString() { ... }
 
         return "UserSwitchResult { " +
-                "status = " + mStatus + ", " +
+                "status = " + statusToString(mStatus) + ", " +
                 "errorMessage = " + mErrorMessage +
         " }";
     }
@@ -260,6 +295,29 @@
         String errorMessage = (flg & 0x2) == 0 ? null : in.readString();
 
         this.mStatus = status;
+
+        if (!(mStatus == STATUS_SUCCESSFUL)
+                && !(mStatus == STATUS_ANDROID_FAILURE)
+                && !(mStatus == STATUS_HAL_FAILURE)
+                && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
+                && !(mStatus == STATUS_INVALID_REQUEST)
+                && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
+                && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
+                && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
+                && !(mStatus == STATUS_NOT_SWITCHABLE)) {
+            throw new java.lang.IllegalArgumentException(
+                    "status was " + mStatus + " but must be one of: "
+                            + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+                            + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+                            + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
+                            + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
+                            + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + "), "
+                            + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
+                            + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
+                            + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
+                            + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + ")");
+        }
+
         this.mErrorMessage = errorMessage;
 
         // onConstructed(); // You can define this method to get a callback
@@ -280,15 +338,14 @@
     };
 
     @DataClass.Generated(
-            time = 1590737883648L,
+            time = 1592422606349L,
             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_INVALID_REQUEST\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_NOT_SWITCHABLE\nprivate final @android.car.user.UserSwitchResult.Status 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() {}
 
 
     //@formatter:on
     // End of generated code
-
 }
diff --git a/car-lib/src/android/car/vms/VmsClient.java b/car-lib/src/android/car/vms/VmsClient.java
index 394ba67..a941909 100644
--- a/car-lib/src/android/car/vms/VmsClient.java
+++ b/car-lib/src/android/car/vms/VmsClient.java
@@ -65,6 +65,7 @@
     private final Executor mExecutor;
     private final VmsClientCallback mCallback;
     private final boolean mLegacyClient;
+    private final IVmsClientCallback mClientCallback;
     private final Consumer<RemoteException> mExceptionHandler;
     private final IBinder mClientToken;
 
@@ -80,11 +81,13 @@
      * @hide
      */
     public VmsClient(IVmsBrokerService service, Executor executor, VmsClientCallback callback,
-            boolean legacyClient, Consumer<RemoteException> exceptionHandler) {
+            boolean legacyClient, boolean autoCloseMemory,
+            Consumer<RemoteException> exceptionHandler) {
         mService = service;
         mExecutor = executor;
         mCallback = callback;
         mLegacyClient = legacyClient;
+        mClientCallback = new IVmsClientCallbackImpl(this, autoCloseMemory);
         mExceptionHandler = exceptionHandler;
         mClientToken = new Binder();
     }
@@ -279,8 +282,8 @@
      * @hide
      */
     public void register() throws RemoteException {
-        VmsRegistrationInfo registrationInfo = mService.registerClient(mClientToken,
-                new IVmsClientCallbackImpl(this), mLegacyClient);
+        VmsRegistrationInfo registrationInfo = mService.registerClient(
+                mClientToken, mClientCallback, mLegacyClient);
         synchronized (mLock) {
             mAvailableLayers = registrationInfo.getAvailableLayers();
             mSubscriptionState = registrationInfo.getSubscriptionState();
@@ -298,9 +301,11 @@
 
     private static class IVmsClientCallbackImpl extends IVmsClientCallback.Stub {
         private final WeakReference<VmsClient> mClient;
+        private final boolean mAutoCloseMemory;
 
-        private IVmsClientCallbackImpl(VmsClient client) {
+        private IVmsClientCallbackImpl(VmsClient client, boolean autoCloseMemory) {
             mClient = new WeakReference<>(client);
+            mAutoCloseMemory = autoCloseMemory;
         }
 
         @Override
@@ -337,15 +342,20 @@
 
         @Override
         public void onLargePacketReceived(int providerId, VmsLayer layer, SharedMemory packet) {
-            try (SharedMemory largePacket = packet) {
-                if (DBG) {
-                    Log.d(TAG, "Received large packet from " + providerId + " for: " + layer
-                            + " (" + largePacket.getSize() + " bytes)");
-                }
-                byte[] packetData = sharedMemoryToPacket(largePacket);
-                executeCallback((client, callback) ->
-                        callback.onPacketReceived(providerId, layer, packetData));
+            if (DBG) {
+                Log.d(TAG, "Received large packet from " + providerId + " for: " + layer
+                        + " (" + packet.getSize() + " bytes)");
             }
+            byte[] largePacket;
+            if (mAutoCloseMemory) {
+                try (SharedMemory autoClosedPacket = packet) {
+                    largePacket = sharedMemoryToPacket(autoClosedPacket);
+                }
+            } else {
+                largePacket = sharedMemoryToPacket(packet);
+            }
+            executeCallback((client, callback) ->
+                    callback.onPacketReceived(providerId, layer, largePacket));
         }
 
         private void executeCallback(BiConsumer<VmsClient, VmsClientCallback> callbackOperation) {
diff --git a/car-lib/src/android/car/vms/VmsClientManager.java b/car-lib/src/android/car/vms/VmsClientManager.java
index c6f8be8..db43342 100644
--- a/car-lib/src/android/car/vms/VmsClientManager.java
+++ b/car-lib/src/android/car/vms/VmsClientManager.java
@@ -127,6 +127,7 @@
             }
 
             client = new VmsClient(mBrokerService, executor, callback, legacyClient,
+                    /* autoCloseMemory */ true,
                     this::handleRemoteExceptionFromCarService);
             mClients.put(callback, client);
             if (DBG) Log.d(TAG, "Client count: " + mClients.size());
diff --git a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
index c89a337..09d2670 100644
--- a/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
+++ b/car-test-lib/src/android/car/test/mocks/AbstractExtendedMockitoTestCase.java
@@ -448,7 +448,6 @@
             Answer<String> getStringAnswer = invocation ->
                     getAnswer(invocation, String.class, 1, INVALID_DEFAULT_INDEX);
 
-
             when(Settings.Global.putInt(any(), any(), anyInt())).thenAnswer(insertObjectAnswer);
 
             when(Settings.Global.getInt(any(), any(), anyInt())).thenAnswer(getIntAnswer);
@@ -459,6 +458,9 @@
             when(Settings.Secure.getIntForUser(any(), any(), anyInt(), anyInt()))
                     .thenAnswer(getIntAnswer);
 
+            when(Settings.Secure.putStringForUser(any(), anyString(), anyString(), anyInt()))
+                    .thenAnswer(insertObjectAnswer);
+
             when(Settings.Global.putString(any(), any(), any()))
                     .thenAnswer(insertObjectAnswer);
 
diff --git a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
index 20925e8..f6b15f2 100644
--- a/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/AndroidMockitoHelper.java
@@ -17,6 +17,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.when;
 
@@ -111,20 +112,28 @@
     }
 
     /**
-     * Mocks {@code UserManager#getUsers(excludeDying)} to return the given users.
+     * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
+     * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return the given
+     * users.
      */
     public static void mockUmGetUsers(@NonNull UserManager um, @NonNull UserInfo... users) {
         Objects.requireNonNull(um);
         List<UserInfo> testUsers = Arrays.stream(users).collect(Collectors.toList());
-        when(um.getUsers(/* excludeDying= */ true)).thenReturn(testUsers);
+        when(um.getUsers()).thenReturn(testUsers);
+        when(um.getUsers(anyBoolean())).thenReturn(testUsers);
+        when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(testUsers);
     }
 
     /**
-     * Mocks {@code UserManager#getUsers(excludeDying)} to return simple users with the given ids.
+     * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
+     * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return simple
+     * users with the given ids.
      */
     public static void mockUmGetUsers(@NonNull UserManager um, @NonNull @UserIdInt int... userIds) {
         List<UserInfo> users = UserTestingHelper.newUsers(userIds);
-        when(um.getUsers(/* excludeDying= */ true)).thenReturn(users);
+        when(um.getUsers()).thenReturn(users);
+        when(um.getUsers(anyBoolean())).thenReturn(users);
+        when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(users);
     }
 
     /**
@@ -136,10 +145,14 @@
     }
 
     /**
-     * Mocks a call to {@code UserManager#getUsers(true)}, which excludes dying users.
+     * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
+     * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return given
+     * userInfos.
      */
     public static void mockUmGetUsers(@NonNull UserManager um, @NonNull List<UserInfo> userInfos) {
-        when(um.getUsers(/* excludeDying= */ true)).thenReturn(userInfos);
+        when(um.getUsers()).thenReturn(userInfos);
+        when(um.getUsers(anyBoolean())).thenReturn(userInfos);
+        when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(userInfos);
     }
 
     /**
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/build/car.mk b/car_product/build/car.mk
index bc61fca..9dd63e1 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -25,8 +25,10 @@
     CompanionDeviceSupport \
     OneTimeInitializer \
     Provision \
+    StatementService \
     SystemUpdater
 
+
 PRODUCT_PACKAGES += \
     clatd \
     clatd.conf \
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 9587c83..0ed7b7f 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -154,6 +154,12 @@
         <install-in user-type="SYSTEM" />
     </install-in-user-type>
 
+    <!-- Required for compatibility -->
+    <install-in-user-type package="com.android.statementservice">
+        <install-in user-type="FULL" />
+        <install-in user-type="SYSTEM" />
+    </install-in-user-type>
+
     <!-- Failed to find provider info for downloads error if not installed for system user -->
     <install-in-user-type package="com.android.providers.downloads">
         <install-in user-type="FULL" />
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/apps/default/EvsStateControl.cpp b/evs/apps/default/EvsStateControl.cpp
index e45fe2f..06af502 100644
--- a/evs/apps/default/EvsStateControl.cpp
+++ b/evs/apps/default/EvsStateControl.cpp
@@ -122,9 +122,22 @@
 }
 
 
-void EvsStateControl::postCommand(const Command& cmd) {
+void EvsStateControl::terminateUpdateLoop() {
+    // Join a rendering thread
+    if (mRenderThread.joinable()) {
+        mRenderThread.join();
+    }
+}
+
+
+void EvsStateControl::postCommand(const Command& cmd, bool clear) {
     // Push the command onto the queue watched by updateLoop
     mLock.lock();
+    if (clear) {
+        std::queue<Command> emptyQueue;
+        std::swap(emptyQueue, mCommandQueue);
+    }
+
     mCommandQueue.push(cmd);
     mLock.unlock();
 
@@ -185,8 +198,9 @@
                 // Send the finished image back for display
                 mDisplay->returnTargetBufferForDisplay(tgtBuffer);
             }
-        } else {
+        } else if (run) {
             // No active renderer, so sleep until somebody wakes us with another command
+            // or exit if we received EXIT command
             std::unique_lock<std::mutex> lock(mLock);
             mWakeSignal.wait(lock);
         }
@@ -194,10 +208,13 @@
 
     LOG(WARNING) << "EvsStateControl update loop ending";
 
-    // TODO:  Fix it so we can exit cleanly from the main thread instead
+    if (mCurrentRenderer) {
+        // Deactive the renderer
+        mCurrentRenderer->deactivate();
+    }
+
     printf("Shutting down app due to state control loop ending\n");
-    LOG(ERROR) << "KILLING THE APP FROM THE EvsStateControl LOOP ON DRAW FAILURE!!!";
-    exit(1);
+    LOG(ERROR) << "Shutting down app due to state control loop ending";
 }
 
 
diff --git a/evs/apps/default/EvsStateControl.h b/evs/apps/default/EvsStateControl.h
index 5ee9f47..1953906 100644
--- a/evs/apps/default/EvsStateControl.h
+++ b/evs/apps/default/EvsStateControl.h
@@ -76,8 +76,11 @@
     // This spawns a new thread that is expected to run continuously
     bool startUpdateLoop();
 
+    // This stops a rendering thread
+    void terminateUpdateLoop();
+
     // Safe to be called from other threads
-    void postCommand(const Command& cmd);
+    void postCommand(const Command& cmd, bool clear = false);
 
 private:
     void updateLoop();
diff --git a/evs/apps/default/evs_app.cpp b/evs/apps/default/evs_app.cpp
index b30bcc7..92d4b7a 100644
--- a/evs/apps/default/evs_app.cpp
+++ b/evs/apps/default/evs_app.cpp
@@ -18,6 +18,7 @@
 #include "EvsStateControl.h"
 #include "EvsVehicleListener.h"
 
+#include <signal.h>
 #include <stdio.h>
 
 #include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
@@ -26,6 +27,7 @@
 #include <android-base/macros.h>    // arraysize
 #include <android-base/strings.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
 #include <hwbinder/ProcessState.h>
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
@@ -38,6 +40,37 @@
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 
+namespace {
+
+android::sp<IEvsEnumerator> pEvs;
+android::sp<IEvsDisplay> pDisplay;
+EvsStateControl *pStateController;
+
+void sigHandler(int sig) {
+    LOG(ERROR) << "evs_app is being terminated on receiving a signal " << sig;
+    if (pEvs != nullptr) {
+        // Attempt to clean up the resources
+        pStateController->postCommand({EvsStateControl::Op::EXIT, 0, 0}, true);
+        pStateController->terminateUpdateLoop();
+        pEvs->closeDisplay(pDisplay);
+    }
+
+    android::hardware::IPCThreadState::self()->stopProcess();
+    exit(EXIT_FAILURE);
+}
+
+void registerSigHandler() {
+    struct sigaction sa;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = sigHandler;
+    sigaction(SIGABRT, &sa, nullptr);
+    sigaction(SIGTERM, &sa, nullptr);
+    sigaction(SIGINT,  &sa, nullptr);
+}
+
+} // namespace
+
 
 // Helper to subscribe to VHal notifications
 static bool subscribeToVHal(sp<IVehicle> pVnet,
@@ -90,6 +123,9 @@
 {
     LOG(INFO) << "EVS app starting";
 
+    // Register a signal handler
+    registerSigHandler();
+
     // Set up default behavior, then check for command line options
     bool useVehicleHal = true;
     bool printHelp = false;
@@ -168,7 +204,7 @@
 
     // Get the EVS manager service
     LOG(INFO) << "Acquiring EVS Enumerator";
-    android::sp<IEvsEnumerator> pEvs = IEvsEnumerator::getService(evsServiceName);
+    pEvs = IEvsEnumerator::getService(evsServiceName);
     if (pEvs.get() == nullptr) {
         LOG(ERROR) << "getService(" << evsServiceName
                    << ") returned NULL.  Exiting.";
@@ -185,7 +221,7 @@
         return EXIT_FAILURE;
     }
 
-    android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId);
+    pDisplay = pEvs->openDisplay_1_1(displayId);
     if (pDisplay.get() == nullptr) {
         LOG(ERROR) << "EVS Display unavailable.  Exiting.";
         return EXIT_FAILURE;
@@ -219,7 +255,7 @@
 
     // Configure ourselves for the current vehicle state at startup
     LOG(INFO) << "Constructing state controller";
-    EvsStateControl *pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
+    pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
     if (!pStateController->startUpdateLoop()) {
         LOG(ERROR) << "Initial configuration failed.  Exiting.";
         return EXIT_FAILURE;
diff --git a/evs/sampleDriver/Android.bp b/evs/sampleDriver/Android.bp
index 1bee713..0ae0b2a 100644
--- a/evs/sampleDriver/Android.bp
+++ b/evs/sampleDriver/Android.bp
@@ -90,6 +90,26 @@
     ],
 }
 
+cc_library{
+    name : "libevsconfigmanager",
+    vendor : true,
+    srcs : [
+        "ConfigManager.cpp",
+        "ConfigManagerUtil.cpp",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.camera.device@3.2",
+        "libbase",
+        "libcamera_metadata",
+        "libcutils",
+        "libhardware",
+        "libtinyxml2",
+        "libutils",
+    ],
+}
+
 prebuilt_etc {
     name: "evs_configuration.dtd",
     soc_specific: true,
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/EvsGlDisplay.cpp b/evs/sampleDriver/EvsGlDisplay.cpp
index f066ef7..949860c 100644
--- a/evs/sampleDriver/EvsGlDisplay.cpp
+++ b/evs/sampleDriver/EvsGlDisplay.cpp
@@ -75,6 +75,7 @@
         alloc.free(mBuffer.memHandle);
         mBuffer.memHandle = nullptr;
 
+        mGlWrapper.hideWindow(mDisplayProxy, mDisplayId);
         mGlWrapper.shutdown();
     }
 
diff --git a/evs/sampleDriver/resources/evs_sample_configuration.xml b/evs/sampleDriver/resources/evs_sample_configuration.xml
index fa3ada3..f81b922 100644
--- a/evs/sampleDriver/resources/evs_sample_configuration.xml
+++ b/evs/sampleDriver/resources/evs_sample_configuration.xml
@@ -197,6 +197,219 @@
                 />
             </characteristics>
         </device>
+
+    <!-- camera device information for v4l2loopback devices -->
+        <!-- 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/video60,/dev/video61,/dev/video62,/dev/video63'
+                />
+            </characteristics>
+        </group>
+
+        <!-- camera device starts  -->
+        <!-- /dev/video6[0-3]$ 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/video60' 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/video61' 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/video62' 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/video63' 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 -->
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 0784958..9501c89 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -60,6 +60,7 @@
 
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -743,7 +744,11 @@
         return false;
     }
 
-    private boolean isMediaService(@NonNull ComponentName componentName) {
+    /**
+     * Returns {@code true} if the provided component has a valid {@link MediaBrowseService}.
+     */
+    @VisibleForTesting
+    public boolean isMediaService(@NonNull ComponentName componentName) {
         return getMediaService(componentName) != null;
     }
 
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/CarServiceUtils.java b/service/src/com/android/car/CarServiceUtils.java
index 781fd6a..046c059 100644
--- a/service/src/com/android/car/CarServiceUtils.java
+++ b/service/src/com/android/car/CarServiceUtils.java
@@ -208,7 +208,7 @@
     public static HandlerThread getHandlerThread(String name) {
         synchronized (sHandlerThreads) {
             HandlerThread thread = sHandlerThreads.get(name);
-            if (thread == null) {
+            if (thread == null || !thread.isAlive()) {
                 Log.i(TAG, "Starting HandlerThread:" + name);
                 thread = new HandlerThread(name);
                 thread.start();
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index 0a8c420..e1282ab 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);
     }
@@ -1296,11 +1304,19 @@
             writer.println("null response");
             return;
         }
+        if (!response.isSuccess()) {
+            writer.printf("failed response: %s\n", response);
+            return;
+        }
         String errorMessage = response.getErrorMessage();
         if (!TextUtils.isEmpty(errorMessage)) {
             writer.printf("Error message: %s\n", errorMessage);
         }
         int[] values = response.getValues();
+        if (values == null) {
+            writer.printf("no associations on %s\n", response);
+            return;
+        }
         writer.printf("%d associations:\n", values.length);
         for (int i = 0; i < values.length; i++) {
             writer.printf("  %s\n", UserIdentificationAssociationValue.toString(values[i]));
diff --git a/service/src/com/android/car/CarUxRestrictionsManagerService.java b/service/src/com/android/car/CarUxRestrictionsManagerService.java
index 176a417..88fc920 100644
--- a/service/src/com/android/car/CarUxRestrictionsManagerService.java
+++ b/service/src/com/android/car/CarUxRestrictionsManagerService.java
@@ -1152,7 +1152,13 @@
             mRemoteCallbackList.register(callback);
             mActivityViewDisplayInfoMap.put(virtualDisplayId,
                     new DisplayInfo(callback, physicalDisplayId));
-            mPortLookup.put(virtualDisplayId, (byte) physicalDisplayId);
+            Byte physicalPort = getPhysicalPortLocked(physicalDisplayId);
+            if (physicalPort == null) {
+                // This should not happen.
+                Log.wtf(TAG, "No known physicalPort for displayId:" + physicalDisplayId);
+                physicalPort = mDefaultDisplayPhysicalPort;
+            }
+            mPortLookup.put(virtualDisplayId, physicalPort);
         }
     }
 
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 3efbd18..db081eb 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -46,7 +46,6 @@
 import android.media.AudioPatch;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioPortConfig;
-import android.media.AudioSystem;
 import android.media.audiopolicy.AudioPolicy;
 import android.os.IBinder;
 import android.os.Looper;
@@ -741,13 +740,11 @@
     }
 
     private void releaseAudioPatchLocked(CarAudioPatchHandle carPatch) {
+        Objects.requireNonNull(carPatch);
         // NOTE:  AudioPolicyService::removeNotificationClient will take care of this automatically
         //        if the client that created a patch quits.
-
-        // FIXME {@link AudioManager#listAudioPatches(ArrayList)} returns old generation of
-        // audio patches after creation
         ArrayList<AudioPatch> patches = new ArrayList<>();
-        int result = AudioSystem.listAudioPatches(patches, new int[1]);
+        int result = mAudioManager.listAudioPatches(patches);
         if (result != AudioManager.SUCCESS) {
             throw new RuntimeException("listAudioPatches failed with code " + result);
         }
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/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index f740f10..f1129f7 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -347,7 +347,8 @@
             return null;
         }
         VmsClient client = new VmsClient(brokerService, new HandlerExecutor(handler), callback,
-                /* legacyClient= */ true, /* exceptionHandler= */ ignored -> { });
+                /* legacyClient= */ true, /* autoCloseMemory */ false,
+                /* exceptionHandler= */ ignored -> { });
         try {
             client.register();
         } catch (RemoteException e) {
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index b9c54a0..e4aeea8 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;
         }
@@ -966,7 +966,7 @@
         if (isUserHalSupported()) {
             RemoveUserRequest request = new RemoveUserRequest();
             request.removedUserInfo = halUser;
-            request.usersInfo = usersInfo;
+            request.usersInfo = UserHalHelper.newUsersInfo(mUserManager);
             mHal.removeUser(request);
         }
 
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
index 02da338..7580795 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",
     ],
 }
 
@@ -112,23 +151,22 @@
     ],
 }
 
-cc_binary{
-    name : "android.automotive.sv.service@1.0-impl",
+cc_library{
+    name : "libsvsession",
     vendor : true,
     srcs : [
+        "CameraUtils.cpp",
         "CoreLibSetupHelper.cpp",
-        "SurroundViewService.cpp",
         "SurroundView2dSession.cpp",
         "SurroundView3dSession.cpp",
-        "VhalHandler.cpp",
-        "service.cpp",
     ],
-    init_rc : ["android.automotive.sv.service@1.0-impl.rc"],
     shared_libs : [
+        "android.hardware.automotive.evs@1.0",
         "android.hardware.automotive.evs@1.1",
         "android.hardware.automotive.sv@1.0",
         "android.hardware.automotive.vehicle@2.0",
         "android.hidl.memory@1.0",
+        "libanimation_module",
         "libbase",
         "libbinder",
         "libcamera_metadata",
@@ -137,14 +175,125 @@
         "libhardware",
         "libhidlbase",
         "libhidlmemory",
+        "libio_module",
         "libui",
         "libutils",
+        "libvhal_handler",
     ],
     required : [
         "cam0.png",
         "cam1.png",
         "cam2.png",
         "cam3.png",
+        "sample_car.obj",
+        "sample_car_material.mtl",
+        "sv_sample_config.xml",
+        "sv_sample_car_model_config.xml",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled : false,
+    arch : {
+        arm64 : {
+            enabled : true,
+        },
+        x86 : {
+            enabled : true,
+        },
+        x86_64 : {
+            enabled : true,
+        },
+    },
+}
+
+cc_test{
+    name : "sv_session_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : [
+        "SurroundViewSessionTests.cpp",
+        "mock-evs/MockEvsCamera.cpp",
+        "mock-evs/MockEvsEnumerator.cpp",
+        "mock-evs/MockSurroundViewCallback.cpp",
+    ],
+    include_dirs: [
+        "packages/services/Car/evs/sampleDriver",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "libanimation_module",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcore_lib_shared",
+        "libcutils",
+        "libevsconfigmanager",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libio_module",
+        "libsvsession",
+        "libtinyxml2",
+        "libui",
+        "libutils",
+        "libvhal_handler",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled : false,
+    arch : {
+        arm64 : {
+            enabled : true,
+        },
+        x86 : {
+            enabled : true,
+        },
+        x86_64 : {
+            enabled : true,
+        },
+    },
+}
+
+cc_binary{
+    name : "android.automotive.sv.service@1.0-impl",
+    vendor : true,
+    srcs : [
+        "SurroundViewService.cpp",
+        "service.cpp",
+    ],
+    init_rc : ["android.automotive.sv.service@1.0-impl.rc"],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "libanimation_module",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcore_lib_shared",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libio_module",
+        "libsvsession",
+        "libui",
+        "libutils",
+        "libvhal_handler",
+    ],
+    cflags: ["-DLOG_TAG=\"SurroundViewService\""],
+    required : [
+        "cam0.png",
+        "cam1.png",
+        "cam2.png",
+        "cam3.png",
+        "sample_car.obj",
+        "sample_car_material.mtl",
+        "sv_sample_config.xml",
+        "sv_sample_car_model_config.xml",
     ],
     // Disable builds except for arm64 and emulator devices
     enabled : false,
@@ -189,35 +338,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..2eecdb0 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,
@@ -156,16 +162,15 @@
 void AnimationModule::updateChildrenParts(const std::string& partId, const Mat4x4& parentModel) {
     for (auto& childPart : mCarPartsStatusMap.at(partId).childIds) {
         mCarPartsStatusMap.at(childPart).parentModel = parentModel;
-        appendMat(parentModel, mCarPartsStatusMap.at(childPart).parentModel);
         mCarPartsStatusMap.at(childPart).currentModel =
                 appendMat(mCarPartsStatusMap.at(childPart).localModel,
                           mCarPartsStatusMap.at(childPart).parentModel);
         if (mUpdatedPartsMap.find(childPart) == mUpdatedPartsMap.end()) {
-            AnimationParam animationParam(partId);
+            AnimationParam animationParam(childPart);
             animationParam.SetModelMatrix(mCarPartsStatusMap.at(childPart).currentModel);
-            mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
+            mUpdatedPartsMap.emplace(std::make_pair(childPart, animationParam));
         } else {  // existing part in the map
-            mUpdatedPartsMap.at(partId).SetModelMatrix(
+            mUpdatedPartsMap.at(childPart).SetModelMatrix(
                     mCarPartsStatusMap.at(childPart).currentModel);
         }
         updateChildrenParts(childPart, mCarPartsStatusMap.at(childPart).currentModel);
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..7be6cb0
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CarModelConfigReader.h"
+#include "ConfigReaderUtil.h"
+#include "MathHelp.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Macro returning IoStatus::ERROR_READ_ANIMATION if condition evaluates to false.
+#define RETURN_ERROR_STATUS_IF_FALSE(cond)         \
+    do {                                           \
+        if (!(cond)) {                             \
+            return IOStatus::ERROR_READ_ANIMATION; \
+        }                                          \
+    } while (0)
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLDocument;
+using tinyxml2::XMLElement;
+
+namespace {
+
+bool ReadValueHex(const XMLElement* parent, const char* elementName, uint32_t* hex) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    *hex = std::stoul(element->GetText(), nullptr, 16);
+    return true;
+}
+
+bool ReadValueList(const XMLElement* parent, const char* elementName,
+                   std::vector<std::string>* valueList) {
+    valueList->clear();
+    for (const XMLElement* elem = parent->FirstChildElement(elementName); elem != nullptr;
+         elem = elem->NextSiblingElement(elementName)) {
+        RETURN_IF_FALSE(ElementHasText(elem));
+        valueList->push_back(std::string(elem->GetText()));
+    }
+    return true;
+}
+
+// ReadValue for SurroundView2dParams::BlendingType.
+bool ReadAnimationType(const XMLElement* parent, const char* elementName, AnimationType* type) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    const std::string animationTypeStr(element->GetText());
+
+    if (animationTypeStr == "RotationAngle") {
+        *type = AnimationType::ROTATION_ANGLE;
+    } else if (animationTypeStr == "RotationSpeed") {
+        *type = AnimationType::ROTATION_SPEED;
+    } else if (animationTypeStr == "Translation") {
+        *type = AnimationType::TRANSLATION;
+    } else if (animationTypeStr == "SwitchTextureOnce") {
+        *type = AnimationType::SWITCH_TEXTURE_ONCE;
+    } else if (animationTypeStr == "AdjustGammaOnce") {
+        *type = AnimationType::ADJUST_GAMMA_ONCE;
+    } else if (animationTypeStr == "SwitchTextureRepeat") {
+        *type = AnimationType::SWITCH_TEXTURE_REPEAT;
+    } else if (animationTypeStr == "AdjustGammaRepeat") {
+        *type = AnimationType::ADJUST_GAMMA_REPEAT;
+    } else {
+        LOG(ERROR) << "Unknown AnimationType specified: " << animationTypeStr;
+        return false;
+    }
+    return true;
+}
+
+bool ReadRange(const XMLElement* parent, const char* elementName, Range* range) {
+    const XMLElement* rangeElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &rangeElem));
+    {
+        RETURN_IF_FALSE(ReadValue(rangeElem, "Start", &range->start));
+        RETURN_IF_FALSE(ReadValue(rangeElem, "End", &range->end));
+    }
+    return true;
+}
+
+bool ReadFloat3(const XMLElement* parent, const char* elementName, std::array<float, 3>* float3) {
+    const XMLElement* arrayElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &arrayElem));
+    {
+        RETURN_IF_FALSE(ReadValue(arrayElem, "X", &float3->at(0)));
+        RETURN_IF_FALSE(ReadValue(arrayElem, "Y", &float3->at(1)));
+        RETURN_IF_FALSE(ReadValue(arrayElem, "Z", &float3->at(2)));
+    }
+    return true;
+}
+
+// Generic template for reading a animation op, each op type must be specialized.
+template <typename OpType>
+bool ReadOp(const XMLElement* opElem, OpType* op) {
+    (void)opElem;
+    (void)op;
+    LOG(ERROR) << "Unexpected internal error: Op type in not supported.";
+    return false;
+}
+
+// Reads vhal property.
+bool ReadVhalProperty(const XMLElement* parent, const char* elementName, uint64_t* vhalProperty) {
+    const XMLElement* vhalPropElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &vhalPropElem));
+    {
+        uint32_t propertyId;
+        uint32_t areaId;
+        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "PropertyId", &propertyId));
+        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "AreaId", &areaId));
+        *vhalProperty = (static_cast<uint64_t>(propertyId) << 32) | areaId;
+    }
+    return true;
+}
+
+template <>
+bool ReadOp<RotationOp>(const XMLElement* rotationOpElem, RotationOp* rotationOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(rotationOpElem, "VhalProperty", &rotationOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(rotationOpElem, "AnimationType", &rotationOp->type));
+
+    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationAxis", &rotationOp->axis.axisVector));
+
+    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationPoint", &rotationOp->axis.rotationPoint));
+
+    RETURN_IF_FALSE(
+            ReadValue(rotationOpElem, "DefaultRotationValue", &rotationOp->defaultRotationValue));
+
+    RETURN_IF_FALSE(ReadValue(rotationOpElem, "AnimationTimeMs", &rotationOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(rotationOpElem, "RotationRange", &rotationOp->rotationRange));
+
+    RETURN_IF_FALSE(ReadRange(rotationOpElem, "VhalRange", &rotationOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<TranslationOp>(const XMLElement* translationOpElem, TranslationOp* translationOp) {
+    RETURN_IF_FALSE(
+            ReadVhalProperty(translationOpElem, "VhalProperty", &translationOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(translationOpElem, "AnimationType", &translationOp->type));
+
+    RETURN_IF_FALSE(ReadFloat3(translationOpElem, "Direction", &translationOp->direction));
+
+    RETURN_IF_FALSE(ReadValue(translationOpElem, "DefaultTranslationValue",
+                              &translationOp->defaultTranslationValue));
+
+    RETURN_IF_FALSE(ReadValue(translationOpElem, "AnimationTimeMs", &translationOp->animationTime));
+
+    RETURN_IF_FALSE(
+            ReadRange(translationOpElem, "TranslationRange", &translationOp->translationRange));
+
+    RETURN_IF_FALSE(ReadRange(translationOpElem, "VhalRange", &translationOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<TextureOp>(const XMLElement* textureOpElem, TextureOp* textureOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(textureOpElem, "VhalProperty", &textureOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(textureOpElem, "AnimationType", &textureOp->type));
+
+    RETURN_IF_FALSE(ReadValue(textureOpElem, "DefaultTexture", &textureOp->defaultTexture));
+
+    RETURN_IF_FALSE(ReadValue(textureOpElem, "AnimationTimeMs", &textureOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(textureOpElem, "TextureRange", &textureOp->textureRange));
+
+    RETURN_IF_FALSE(ReadRange(textureOpElem, "VhalRange", &textureOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<GammaOp>(const XMLElement* gammaOpElem, GammaOp* gammaOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(gammaOpElem, "VhalProperty", &gammaOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(gammaOpElem, "AnimationType", &gammaOp->type));
+
+    RETURN_IF_FALSE(ReadValue(gammaOpElem, "AnimationTimeMs", &gammaOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(gammaOpElem, "GammaRange", &gammaOp->gammaRange));
+
+    RETURN_IF_FALSE(ReadRange(gammaOpElem, "VhalRange", &gammaOp->vhalRange));
+
+    return true;
+}
+
+template <typename OpType>
+bool ReadAllOps(const XMLElement* animationElem, const char* elemName,
+                std::map<uint64_t, std::vector<OpType>>* mapOps) {
+    for (const XMLElement* elem = animationElem->FirstChildElement(elemName); elem != nullptr;
+         elem = elem->NextSiblingElement(elemName)) {
+        OpType op;
+        RETURN_IF_FALSE(ReadOp(elem, &op));
+        if (mapOps->find(op.vhalProperty) == mapOps->end()) {
+            mapOps->emplace(op.vhalProperty, std::vector<OpType>());
+        }
+        mapOps->at(op.vhalProperty).push_back(op);
+    }
+    return true;
+}
+
+bool ReadAnimation(const XMLElement* animationElem, AnimationInfo* animationInfo) {
+    RETURN_IF_FALSE(ReadValue(animationElem, "PartId", &animationInfo->partId));
+    RETURN_IF_FALSE(ReadValue(animationElem, "ParentPartId", &animationInfo->parentId));
+
+    // Child Part Ids (Optional)
+    const XMLElement* childPartsElem = nullptr;
+    GetElement(animationElem, "ChildParts", &childPartsElem);
+    if (childPartsElem != nullptr) {
+        RETURN_IF_FALSE(ReadValueList(childPartsElem, "PartId", &animationInfo->childIds));
+    }
+
+    // Set to the default Identity.
+    animationInfo->pose = gMat4Identity;
+
+    // All animation operations.
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "RotationOp", &animationInfo->rotationOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "TranslationOp", &animationInfo->translationOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "TextureOp", &animationInfo->textureOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "GammaOp", &animationInfo->gammaOpsMap));
+    return true;
+}
+
+bool ReadAllAnimations(const XMLElement* rootElem, std::vector<AnimationInfo>* animations) {
+    animations->clear();
+    // Loop over animation elements.
+    for (const XMLElement* elem = rootElem->FirstChildElement("Animation"); elem != nullptr;
+         elem = elem->NextSiblingElement("Animation")) {
+        AnimationInfo animationInfo;
+        RETURN_IF_FALSE(ReadAnimation(elem, &animationInfo));
+        animations->push_back(animationInfo);
+    }
+    return true;
+}
+
+}  // namespace
+
+IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
+                            AnimationConfig* animationConfig) {
+    XMLDocument xmlDoc;
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(carModelConfigFile.c_str());
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
+        return IOStatus::ERROR_READ_ANIMATION;
+    }
+
+    const XMLElement* rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "SurroundViewCarModelConfig")) {
+        LOG(ERROR) << "Config file is not in the required format: " << carModelConfigFile;
+        return IOStatus::ERROR_READ_ANIMATION;
+    }
+
+    // version
+    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &animationConfig->version));
+
+    // animations
+    RETURN_ERROR_STATUS_IF_FALSE(ReadAllAnimations(rootElem, &animationConfig->animations));
+
+    return IOStatus::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/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..cc97d4e
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigReader.h"
+#include "ConfigReaderUtil.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLDocument;
+using tinyxml2::XMLElement;
+
+using android_auto::surround_view::SurroundView2dParams;
+using android_auto::surround_view::SurroundView3dParams;
+
+namespace {
+
+// Macro returning IoStatus::ERROR_CONFIG_FILE_FORMAT if condition evaluates to false.
+#define RETURN_ERROR_STATUS_IF_FALSE(cond)             \
+    do {                                               \
+        if (!(cond)) {                                 \
+            return IOStatus::ERROR_CONFIG_FILE_FORMAT; \
+        }                                              \
+    } while (0)
+
+// ReadValue for SurroundView2dParams::BlendingType.
+bool ReadValue2dBlendType(const XMLElement* parent, const char* elementName,
+                          SurroundView2dParams::BlendingType* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    const std::string blendingTypeStr(element->GetText());
+
+    if (blendingTypeStr == "multiband") {
+        *value = SurroundView2dParams::BlendingType::MULTIBAND;
+    } else if (blendingTypeStr == "alpha") {
+        *value = SurroundView2dParams::BlendingType::ALPHA;
+    } else {
+        LOG(ERROR) << "Unknown BlendingType specified: " << blendingTypeStr;
+        return false;
+    }
+    return true;
+}
+
+bool ReadSvConfig2d(const XMLElement* parent, SvConfig2d* sv2dConfig) {
+    RETURN_IF_FALSE(ReadValue(parent, "Sv2dEnabled", &sv2dConfig->sv2dEnabled));
+    if (!sv2dConfig->sv2dEnabled) {
+        return true;
+    }
+
+    SurroundView2dParams* sv2dParams = &sv2dConfig->sv2dParams;
+    const XMLElement* param2dElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "Sv2dParams", &param2dElem));
+    {
+        // OutputResolution
+        const XMLElement* outputResolutionElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "OutputResolution", &outputResolutionElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Width", &sv2dParams->resolution.width));
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Height", &sv2dParams->resolution.height));
+        }
+
+        // GroundMapping
+        const XMLElement* groundMappingElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "GroundMapping", &groundMappingElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(groundMappingElem, "Width", &sv2dParams->physical_size.width));
+            RETURN_IF_FALSE(
+                    ReadValue(groundMappingElem, "Height", &sv2dParams->physical_size.height));
+
+            // Center
+            const XMLElement* centerElem = nullptr;
+            RETURN_IF_FALSE(GetElement(groundMappingElem, "Center", &centerElem));
+            {
+                RETURN_IF_FALSE(ReadValue(centerElem, "X", &sv2dParams->physical_center.x));
+                RETURN_IF_FALSE(ReadValue(centerElem, "Y", &sv2dParams->physical_center.y));
+            }
+        }
+
+        // Car Bounding Box
+        const XMLElement* carBoundingBoxElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "CarBoundingBox", &carBoundingBoxElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(carBoundingBoxElem, "Width", &sv2dConfig->carBoundingBox.width));
+            RETURN_IF_FALSE(
+                    ReadValue(carBoundingBoxElem, "Height", &sv2dConfig->carBoundingBox.height));
+
+            // Center
+            const XMLElement* leftTopCornerElem = nullptr;
+            RETURN_IF_FALSE(GetElement(carBoundingBoxElem, "LeftTopCorner", &leftTopCornerElem));
+            {
+                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "X", &sv2dConfig->carBoundingBox.x));
+                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "Y", &sv2dConfig->carBoundingBox.y));
+            }
+        }
+
+        // Blending type
+        const XMLElement* blendingTypeElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "BlendingType", &blendingTypeElem));
+        {
+            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "HighQuality",
+                                                 &sv2dParams->high_quality_blending));
+            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "LowQuality",
+                                                 &sv2dParams->low_quality_blending));
+        }
+    }
+    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..e5fe7c4
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigReaderUtil.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <utility>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLElement;
+
+bool ElementHasText(const XMLElement* element) {
+    if (element->GetText() == "") {
+        LOG(ERROR) << "Expected element to have text: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool GetElement(const XMLElement* parent, const char* elementName, XMLElement const** element) {
+    *element = parent->FirstChildElement(elementName);
+    if (*element == nullptr) {
+        LOG(ERROR) << "Expected element '" << elementName << "' in parent '" << parent->Name()
+                   << "' not found";
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, bool* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryBoolText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid boolean value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, std::string* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    *value = std::string(element->GetText());
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, float* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryFloatText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid float value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, int* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryIntText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid int value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/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..e1af11a
--- /dev/null
+++ b/surround_view/service-impl/IOModule.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "CarModelConfigReader.h"
+#include "ConfigReader.h"
+#include "IOModule.h"
+#include "ObjReader.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+IOModule::IOModule(const std::string& svConfigFile) :
+      mSvConfigFile(svConfigFile), mIsInitialized(false) {}
+
+IOStatus IOModule::initialize() {
+    if (mIsInitialized) {
+        LOG(INFO) << "IOModule is already initialized.";
+        return IOStatus::OK;
+    }
+
+    SurroundViewConfig svConfig;
+    IOStatus status;
+    if ((status = ReadSurroundViewConfig(mSvConfigFile, &svConfig)) != IOStatus::OK) {
+        LOG(ERROR) << "ReadSurroundViewConfig() failed.";
+        return status;
+    }
+
+    mIOModuleConfig.cameraConfig = svConfig.cameraConfig;
+    mIOModuleConfig.sv2dConfig = svConfig.sv2dConfig;
+    mIOModuleConfig.sv3dConfig = svConfig.sv3dConfig;
+
+    if (mIOModuleConfig.sv3dConfig.sv3dEnabled) {
+        // Read obj and mtl files.
+        if (!ReadObjFromFile(svConfig.sv3dConfig.carModelObjFile,
+                             &mIOModuleConfig.carModelConfig.carModel.partsMap)) {
+            LOG(ERROR) << "ReadObjFromFile() failed.";
+            return IOStatus::ERROR_READ_CAR_MODEL;
+        }
+        // Read animations.
+        if (mIOModuleConfig.sv3dConfig.sv3dAnimationsEnabled) {
+            if ((status = ReadCarModelConfig(svConfig.sv3dConfig.carModelConfigFile,
+                                             &mIOModuleConfig.carModelConfig.animationConfig)) !=
+                IOStatus::OK) {
+                LOG(ERROR) << "ReadObjFromFile() failed.";
+                return status;
+            }
+        }
+    }
+    mIsInitialized = true;
+    return IOStatus::OK;
+}
+
+bool IOModule::getConfig(IOModuleConfig* ioModuleConfig) {
+    if (!mIsInitialized) {
+        LOG(ERROR) << "IOModule not initalized.";
+        return false;
+    }
+    *ioModuleConfig = mIOModuleConfig;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/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..7caccec 100644
--- a/surround_view/service-impl/MtlReader.cpp
+++ b/surround_view/service-impl/MtlReader.cpp
@@ -13,13 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #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..dcb1973 100644
--- a/surround_view/service-impl/ObjReader.cpp
+++ b/surround_view/service-impl/ObjReader.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include "ObjReader.h"
 
 #include <array>
diff --git a/surround_view/service-impl/SurroundView2dSession.cpp b/surround_view/service-impl/SurroundView2dSession.cpp
index 4ff62fb..b50049c 100644
--- a/surround_view/service-impl/SurroundView2dSession.cpp
+++ b/surround_view/service-impl/SurroundView2dSession.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "SurroundViewService"
 
 #include "SurroundView2dSession.h"
 
@@ -26,6 +25,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 +74,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 +105,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 +218,7 @@
                 break;
             }
 
-            mFramesSignal.wait(lock, [this]() {
-                return mFramesAvailable;
-            });
+            mFramesSignal.wait(lock, [this]() { return mProcessingEvsFrames; });
         }
 
         handleFrames(mSequenceId);
@@ -218,7 +226,7 @@
         {
             // Set the boolean to false to receive the next set of frames.
             scoped_lock<mutex> lock(mAccessLock);
-            mFramesAvailable = false;
+            mProcessingEvsFrames = false;
         }
     }
 
@@ -234,8 +242,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 +296,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 +329,7 @@
     LOG(DEBUG) << __FUNCTION__;
     scoped_lock <mutex> lock(mAccessLock);
 
-    framesRecord.inUse = false;
+    mFramesRecord.inUse = false;
 
     (void)svFramesDesc;
     return {};
@@ -363,48 +374,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 +431,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 +526,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 +555,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,31 +567,36 @@
     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);
-
-    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];
+    if (mSurroundView->Start2dPipeline()) {
+        LOG(INFO) << "Start2dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start2dPipeline failed";
+        return false;
     }
-    LOG(INFO) << "Allocated 4 input pointers";
 
-    mOutputWidth = Get2dParams().resolution.width;
-    mOutputHeight = Get2dParams().resolution.height;
+    mInputPointers.resize(kNumFrames);
+    for (int i = 0; i < kNumFrames; i++) {
+        mInputPointers[i].width = mCameraParams[i].size.width;
+        mInputPointers[i].height = mCameraParams[i].size.height;
+        mInputPointers[i].format = Format::RGB;
+        mInputPointers[i].cpu_data_pointer =
+                (void*)new uint8_t[mInputPointers[i].width *
+                                   mInputPointers[i].height *
+                                   kNumChannels];
+    }
+    LOG(INFO) << "Allocated " << kNumFrames << " input pointers";
+
+    mOutputWidth = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.width;
+    mOutputHeight = mIOModuleConfig->sv2dConfig.sv2dParams.resolution.height;
 
     mConfig.width = mOutputWidth;
     mConfig.blending = SvQuality::HIGH;
@@ -586,12 +620,12 @@
                                    GRALLOC_USAGE_HW_TEXTURE,
                                    "SvTexture");
 
-    //TODO(b/150412555): the 2d mapping info should be read from config file.
-    mInfo.width = 8;
-    mInfo.height = 6;
+    // Note: sv2dParams is in meters while mInfo must be in milli-meters.
+    mInfo.width = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.width * 1000.0;
+    mInfo.height = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.height * 1000.0;
     mInfo.center.isValid = true;
-    mInfo.center.x = 0;
-    mInfo.center.y = 0;
+    mInfo.center.x = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.x * 1000.0;
+    mInfo.center.y = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.y * 1000.0;
 
     if (mSvTexture->initCheck() == OK) {
         LOG(INFO) << "Successfully allocated Graphic Buffer";
@@ -600,32 +634,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 +711,29 @@
         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);
+
+    for (auto& camera : mCameraParams) {
+        camera.size.width = targetCfg->width;
+        camera.size.height = targetCfg->height;
+        camera.circular_fov = 179;
+    }
+
     return true;
 }
 
@@ -709,4 +756,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..1a91e0d 100644
--- a/surround_view/service-impl/SurroundView3dSession.cpp
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "SurroundViewService"
 
 #include "SurroundView3dSession.h"
 
@@ -30,6 +29,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 +57,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 +70,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 +147,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 +228,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 +252,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 +307,7 @@
     }
     mStream = stream;
 
-    sequenceId = 0;
+    mSequenceId = 0;
     startEvs();
 
     if (mVhalHandler != nullptr) {
@@ -231,6 +323,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 +361,7 @@
     LOG(DEBUG) << __FUNCTION__;
     scoped_lock <mutex> lock(mAccessLock);
 
-    framesRecord.inUse = false;
+    mFramesRecord.inUse = false;
 
     (void)svFramesDesc;
     return {};
@@ -402,35 +495,53 @@
 }
 
 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);
+        // Convert projPoint3d in meters to point3d which is in milli-meters.
+        point3d.x = projPoint3d.x * 1000.0;
+        point3d.y = projPoint3d.y * 1000.0;
+        point3d.z = projPoint3d.z * 1000.0;
         points3d.push_back(point3d);
     }
     _hidl_cb(points3d);
@@ -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,30 @@
     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(kNumFrames);
+    for (int i = 0; i < kNumFrames; i++) {
+        mInputPointers[i].width = mCameraParams[i].size.width;
+        mInputPointers[i].height = mCameraParams[i].size.height;
+        mInputPointers[i].format = Format::RGB;
+        mInputPointers[i].cpu_data_pointer =
+                (void*)new uint8_t[mInputPointers[i].width *
+                                   mInputPointers[i].height *
+                                   kNumChannels];
     }
+    LOG(INFO) << "Allocated " << kNumFrames << " 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 +777,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 +855,29 @@
         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);
+
+    for (auto& camera : mCameraParams) {
+        camera.size.width = targetCfg->width;
+        camera.size.height = targetCfg->height;
+        camera.circular_fov = 179;
+    }
+
     return true;
 }
 
@@ -745,4 +900,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..910b0ae 100644
--- a/surround_view/service-impl/SurroundViewService.cpp
+++ b/surround_view/service-impl/SurroundViewService.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "SurroundViewService"
 
 #include <android-base/logging.h>
 
@@ -39,10 +38,12 @@
 
 SurroundViewService::SurroundViewService() {
     mVhalHandler = new VhalHandler();
+    mIOModule = new IOModule("/vendor/etc/automotive/sv/sv_sample_config.xml");
 }
 
 SurroundViewService::~SurroundViewService() {
     delete mVhalHandler;
+    delete mAnimationModule;
 }
 
 sp<SurroundViewService> SurroundViewService::getInstance() {
@@ -58,6 +59,30 @@
     return sService;
 }
 
+std::vector<uint64_t> getAnimationPropertiesToRead(const AnimationConfig& animationConfig) {
+    std::set<uint64_t> propertiesSet;
+    for(const auto& animation: animationConfig.animations) {
+        for(const auto& opPair : animation.gammaOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+
+        for(const auto& opPair : animation.textureOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+
+        for(const auto& opPair : animation.rotationOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+
+        for(const auto& opPair : animation.translationOpsMap) {
+            propertiesSet.insert(opPair.first);
+        }
+    }
+    std::vector<uint64_t> propertiesToRead;
+    propertiesToRead.assign(propertiesSet.begin(), propertiesSet.end());
+    return propertiesToRead;
+}
+
 bool SurroundViewService::initialize() {
     // Get the EVS manager service
     LOG(INFO) << "Acquiring EVS Enumerator";
@@ -67,11 +92,44 @@
         return false;
     }
 
+    IOStatus status = mIOModule->initialize();
+    if (status != IOStatus::OK) {
+        LOG(ERROR) << "IO Module cannot be initialized properly";
+        return false;
+    }
+
+    if (!mIOModule->getConfig(&mConfig)) {
+        LOG(ERROR) << "Cannot parse Car Config file properly";
+        return false;
+    }
+
+    // Since we only keep one instance of the SurroundViewService and initialize
+    // method is always called after the constructor, it is safe to put the
+    // allocation here and the de-allocation in service's constructor.
+    mAnimationModule = new AnimationModule(
+            mConfig.carModelConfig.carModel.partsMap,
+            mConfig.carModelConfig.carModel.texturesMap,
+            mConfig.carModelConfig.animationConfig.animations);
+
     // Initialize the VHal Handler with update method and rate.
     // TODO(b/157498592): The update rate should align with the EVS camera
     // update rate.
     if (mVhalHandler->initialize(VhalHandler::GET, kVhalUpdateRate)) {
-        mVhalHandler->setPropertiesToRead(vector<VehiclePropValue>());
+        // Initialize the vhal handler properties to read.
+        std::vector<uint64_t> propertiesToRead;
+
+        // Add animation properties to read if 3d and animations are enabled.
+        if (mConfig.sv3dConfig.sv3dEnabled && mConfig.sv3dConfig.sv3dAnimationsEnabled) {
+            const std::vector<uint64_t> animationPropertiesToRead =
+                    getAnimationPropertiesToRead(mConfig.carModelConfig.animationConfig);
+            propertiesToRead.insert(propertiesToRead.end(), animationPropertiesToRead.begin(),
+                    animationPropertiesToRead.end());
+        }
+
+        // Call vhal handler setPropertiesToRead with all properties.
+        if (!mVhalHandler->setPropertiesToRead(propertiesToRead)) {
+            LOG(WARNING) << "VhalHandler setPropertiesToRead failed.";
+        }
     } else {
         LOG(WARNING) << "VhalHandler cannot be initialized properly";
     }
@@ -94,7 +152,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 +184,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 {
@@ -156,4 +217,3 @@
 }  // namespace automotive
 }  // namespace hardware
 }  // namespace android
-
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/SurroundViewSessionTests.cpp b/surround_view/service-impl/SurroundViewSessionTests.cpp
new file mode 100644
index 0000000..b694aaf
--- /dev/null
+++ b/surround_view/service-impl/SurroundViewSessionTests.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 "SurroundViewSessionTests"
+
+#include "mock-evs/MockEvsEnumerator.h"
+#include "mock-evs/MockSurroundViewCallback.h"
+
+#include "IOModule.h"
+#include "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+#include <android-base/logging.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
+
+TEST(SurroundViewSessionTests, startAndStopSurroundView2dSession) {
+    sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
+    IOModule* ioModule = new IOModule(kSvConfigFilename);
+    EXPECT_EQ(ioModule->initialize(), IOStatus::OK);
+
+    IOModuleConfig config;
+    ioModule->getConfig(&config);
+
+    sp<SurroundView2dSession> sv2dSession =
+            new SurroundView2dSession(fakeEvs, &config);
+
+    EXPECT_TRUE(sv2dSession->initialize());
+
+    sp<MockSurroundViewCallback> sv2dCallback =
+            new MockSurroundViewCallback(sv2dSession);
+
+    EXPECT_EQ(sv2dSession->startStream(sv2dCallback), SvResult::OK);
+
+    sv2dSession->stopStream();
+}
+
+TEST(SurroundViewSessionTests, startAndStopSurroundView3dSession) {
+    sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
+    IOModule* ioModule = new IOModule(kSvConfigFilename);
+    EXPECT_EQ(ioModule->initialize(), IOStatus::OK);
+
+    IOModuleConfig config;
+    ioModule->getConfig(&config);
+
+    sp<SurroundView3dSession> sv3dSession =
+            new SurroundView3dSession(fakeEvs,
+                                      nullptr, /* VhalHandler */
+                                      nullptr, /* AnimationModule */
+                                      &config);
+
+    EXPECT_TRUE(sv3dSession->initialize());
+
+    sp<MockSurroundViewCallback> sv3dCallback =
+            new MockSurroundViewCallback(sv3dSession);
+
+    View3d view = {};
+    vector<View3d> views;
+    views.emplace_back(view);
+    sv3dSession->setViews(views);
+
+    EXPECT_EQ(sv3dSession->startStream(sv3dCallback), SvResult::OK);
+
+    sv3dSession->stopStream();
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/VhalHandler.cpp b/surround_view/service-impl/VhalHandler.cpp
index f1294d9..79ced83 100644
--- a/surround_view/service-impl/VhalHandler.cpp
+++ b/surround_view/service-impl/VhalHandler.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "VhalHandler"
 
 #include "VhalHandler.h"
 
@@ -96,18 +95,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 +174,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/mock-evs/MockEvsCamera.cpp b/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
new file mode 100644
index 0000000..f268e5b
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockEvsCamera.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+MockEvsCamera::MockEvsCamera() {
+    mConfigManager =
+            ConfigManager::Create(
+                    "/vendor/etc/automotive/evs/evs_sample_configuration.xml");
+}
+
+Return<void> MockEvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<EvsResult> MockEvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+    // Not implemented.
+
+    (void)bufferCount;
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::startVideoStream(
+        const ::android::sp<IEvsCameraStream_1_0>& stream) {
+    LOG(INFO) << __FUNCTION__;
+
+    (void)stream;
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+    // Not implemented.
+
+    (void)buffer;
+    return {};
+}
+
+Return<void> MockEvsCamera::stopVideoStream() {
+    LOG(INFO) << __FUNCTION__;
+    return {};
+}
+
+Return<int32_t> MockEvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    return 0;
+}
+
+Return<EvsResult> MockEvsCamera::setExtendedInfo(uint32_t opaqueIdentifier,
+                                                 int32_t opaqueValue) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    (void)opaqueValue;
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::getPhysicalCameraInfo(
+        const hidl_string& deviceId, getPhysicalCameraInfo_cb _hidl_cb) {
+    CameraDesc_1_1 desc = {};
+    desc.v1.cameraId = deviceId;
+
+    unique_ptr<ConfigManager::CameraInfo>& cameraInfo =
+            mConfigManager->getCameraInfo(deviceId);
+    if (cameraInfo != nullptr) {
+        desc.metadata.setToExternal(
+                (uint8_t*)cameraInfo->characteristics,
+                get_camera_metadata_size(cameraInfo->characteristics));
+    }
+
+    _hidl_cb(desc);
+
+    return {};
+}
+
+Return<EvsResult> MockEvsCamera::doneWithFrame_1_1(
+        const hardware::hidl_vec<BufferDesc_1_1>& buffer) {
+    // Not implemented.
+
+    (void)buffer;
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::setMaster() {
+    // Not implemented.
+
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::forceMaster(
+        const sp<IEvsDisplay_1_0>& display) {
+    // Not implemented.
+
+    (void)display;
+    return EvsResult::OK;
+}
+
+Return<EvsResult> MockEvsCamera::unsetMaster() {
+    // Not implemented.
+
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::getIntParameterRange(
+        CameraParam id, getIntParameterRange_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)id;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::setIntParameter(CameraParam id, int32_t value,
+                                            setIntParameter_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)id;
+    (void)value;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::getIntParameter(
+        CameraParam id, getIntParameter_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)id;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<EvsResult> MockEvsCamera::setExtendedInfo_1_1(
+    uint32_t opaqueIdentifier, const hidl_vec<uint8_t>& opaqueValue) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    (void)opaqueValue;
+    return EvsResult::OK;
+}
+
+Return<void> MockEvsCamera::getExtendedInfo_1_1(
+        uint32_t opaqueIdentifier, getExtendedInfo_1_1_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)opaqueIdentifier;
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<void> MockEvsCamera::importExternalBuffers(
+        const hidl_vec<BufferDesc_1_1>& buffers,
+        importExternalBuffers_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)buffers;
+    (void)_hidl_cb;
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockEvsCamera.h b/surround_view/service-impl/mock-evs/MockEvsCamera.h
new file mode 100644
index 0000000..d393702
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsCamera.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+
+#include <ConfigManager.h>
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+
+// A simplified implementation for Evs Camera. Only necessary methods are
+// implemented.
+class MockEvsCamera : public IEvsCamera_1_1 {
+public:
+    MockEvsCamera();
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+    Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+    Return<void> doneWithFrame(const BufferDesc_1_0& buffer) override;
+    Return<void> stopVideoStream() override;
+    Return<int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override;
+    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+    Return<void> getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) override;
+    Return<void> getPhysicalCameraInfo(const hidl_string& deviceId,
+                                       getPhysicalCameraInfo_cb _hidl_cb) override;
+    Return<EvsResult> doneWithFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<EvsResult> pauseVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
+    Return<EvsResult> resumeVideoStream() override { return EvsResult::UNDERLYING_SERVICE_ERROR; }
+    Return<EvsResult> setMaster() override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>& display) override;
+    Return<EvsResult> unsetMaster() override;
+    Return<void> getParameterList(getParameterList_cb _hidl_cb) override;
+    Return<void> getIntParameterRange(CameraParam id, getIntParameterRange_cb _hidl_cb) override;
+    Return<void> setIntParameter(CameraParam id, int32_t value,
+                                 setIntParameter_cb _hidl_cb) override;
+    Return<void> getIntParameter(CameraParam id, getIntParameter_cb _hidl_cb) override;
+    Return<EvsResult> setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          const hidl_vec<uint8_t>& opaqueValue) override;
+    Return<void> getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                     getExtendedInfo_1_1_cb _hidl_cb) override;
+    Return<void> importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                       importExternalBuffers_cb _hidl_cb) override;
+
+private:
+    std::unique_ptr<ConfigManager> mConfigManager;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp b/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
new file mode 100644
index 0000000..946083c
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockEvsEnumerator.h"
+#include "MockEvsCamera.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+
+MockEvsEnumerator::MockEvsEnumerator() {
+    mConfigManager = ConfigManager::Create(
+            "/vendor/etc/automotive/evs/evs_sample_configuration.xml");
+}
+
+Return<void> MockEvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<sp<IEvsCamera_1_0>> MockEvsEnumerator::openCamera(
+        const hidl_string& cameraId) {
+    // Not implemented.
+
+    (void)cameraId;
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::closeCamera(
+        const sp<IEvsCamera_1_0>& virtualCamera) {
+    // Not implemented.
+
+    (void)virtualCamera;
+    return {};
+}
+
+Return<sp<IEvsDisplay_1_0>> MockEvsEnumerator::openDisplay() {
+    // Not implemented.
+
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::closeDisplay(
+        const sp<IEvsDisplay_1_0>& display) {
+    // Not implemented.
+
+    (void)display;
+    return {};
+}
+
+Return<EvsDisplayState> MockEvsEnumerator::getDisplayState() {
+    // Not implemented.
+
+    return EvsDisplayState::DEAD;
+}
+
+Return<void> MockEvsEnumerator::getCameraList_1_1(
+        getCameraList_1_1_cb _hidl_cb) {
+    // We only take camera group into consideration here.
+    vector<string> cameraGroupIdList = mConfigManager->getCameraGroupIdList();
+    LOG(INFO) << "getCameraGroupIdList: " << cameraGroupIdList.size();
+    for (int i = 0; i < cameraGroupIdList.size(); i++) {
+        LOG(INFO) << "Camera[" << i << "]: " << cameraGroupIdList[i];
+    }
+
+    vector<CameraDesc_1_1> hidlCameras;
+    for (int i = 0; i < cameraGroupIdList.size(); i++) {
+        CameraDesc_1_1 desc = {};
+        desc.v1.cameraId = cameraGroupIdList[i];
+        unique_ptr<ConfigManager::CameraGroupInfo>& cameraGroupInfo =
+                mConfigManager->getCameraGroupInfo(cameraGroupIdList[i]);
+        if (cameraGroupInfo != nullptr) {
+            desc.metadata.setToExternal(
+                    (uint8_t*)cameraGroupInfo->characteristics,
+                    get_camera_metadata_size(cameraGroupInfo->characteristics));
+        } else {
+            LOG(WARNING) << "Cannot find camera info for "
+                         << cameraGroupIdList[i];
+        }
+        hidlCameras.emplace_back(desc);
+    }
+    _hidl_cb(hidlCameras);
+
+    return {};
+}
+
+Return<sp<IEvsCamera_1_1>> MockEvsEnumerator::openCamera_1_1(
+        const hidl_string& cameraId, const Stream& streamCfg) {
+    // Not implemented.
+
+    (void)cameraId;
+    (void)streamCfg;
+    return new MockEvsCamera();
+}
+
+Return<void> MockEvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
+    // Not implemented.
+
+    (void)_list_cb;
+    return {};
+}
+
+Return<sp<IEvsDisplay_1_1>> MockEvsEnumerator::openDisplay_1_1(uint8_t id) {
+    // Not implemented.
+
+    (void)id;
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::getUltrasonicsArrayList(
+        getUltrasonicsArrayList_cb _hidl_cb) {
+    // Not implemented.
+
+    (void)_hidl_cb;
+    return {};
+}
+
+Return<sp<IEvsUltrasonicsArray>> MockEvsEnumerator::openUltrasonicsArray(
+        const hidl_string& ultrasonicsArrayId) {
+    // Not implemented.
+
+    (void)ultrasonicsArrayId;
+    return nullptr;
+}
+
+Return<void> MockEvsEnumerator::closeUltrasonicsArray(
+        const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) {
+    // Not implemented.
+
+    (void)evsUltrasonicsArray;
+    return {};
+}
+
+Return<void> MockEvsEnumerator::debug(
+        const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    // Not implemented.
+
+    (void)fd;
+    (void)options;
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockEvsEnumerator.h b/surround_view/service-impl/mock-evs/MockEvsEnumerator.h
new file mode 100644
index 0000000..7c1f8b0
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockEvsEnumerator.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
+
+#include <ConfigManager.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::camera::device::V3_2::Stream;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+
+class MockEvsEnumerator : public IEvsEnumerator_1_1 {
+public:
+    MockEvsEnumerator();
+
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+    Return<void> getCameraList(getCameraList_cb _hidl_cb) override;
+    Return<sp<IEvsCamera_1_0>> openCamera(const hidl_string& cameraId) override;
+    Return<void> closeCamera(const ::android::sp<IEvsCamera_1_0>& virtualCamera) override;
+    Return<sp<IEvsDisplay_1_0>> openDisplay() override;
+    Return<void> closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display) override;
+    Return<EvsDisplayState> getDisplayState() override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+    Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb) override;
+    Return<sp<IEvsCamera_1_1>> openCamera_1_1(const hidl_string& cameraId,
+                                              const Stream& streamCfg) override;
+    Return<bool> isHardware() override { return false; }
+    Return<void> getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t id) override;
+    Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
+    Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
+            const hidl_string& ultrasonicsArrayId) override;
+    Return<void> closeUltrasonicsArray(
+            const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) override;
+
+    // Methods from ::android.hidl.base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+private:
+    std::unique_ptr<ConfigManager> mConfigManager;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
new file mode 100644
index 0000000..d059f72
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockSurroundViewCallback.h"
+
+#include <android-base/logging.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+MockSurroundViewCallback::MockSurroundViewCallback(
+        sp<ISurroundViewSession> pSession) {
+    (void)pSession;
+}
+
+Return<void> MockSurroundViewCallback::notify(SvEvent svEvent) {
+    LOG(INFO) << __FUNCTION__ << "SvEvent received: " << (int)svEvent;
+    return {};
+}
+
+Return<void> MockSurroundViewCallback::receiveFrames(
+        const SvFramesDesc& svFramesDesc) {
+    LOG(INFO) << __FUNCTION__ << svFramesDesc.svBuffers.size()
+              << " frames are received";
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
new file mode 100644
index 0000000..7239bf6
--- /dev/null
+++ b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+
+using namespace android::hardware::automotive::sv::V1_0;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class MockSurroundViewCallback : public ISurroundViewStream {
+public:
+    MockSurroundViewCallback(android::sp<ISurroundViewSession> pSession);
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewStream.
+    android::hardware::Return<void> notify(SvEvent svEvent) override;
+    android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/service.cpp b/surround_view/service-impl/service.cpp
index a7ce6f3..3ccc68f 100644
--- a/surround_view/service-impl/service.cpp
+++ b/surround_view/service-impl/service.cpp
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "SurroundViewService"
 
 #include <android-base/logging.h>
 #include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
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..aaa2f1b
--- /dev/null
+++ b/surround_view/service-impl/test_data/sample_car_material.mtl
@@ -0,0 +1,18 @@
+# Sample material file for car model.
+# referenced by sample_car.obj
+
+newmtl door
+    d 1.0000
+    illum 1
+    Ka 0.5000 0.5000 0.5000
+    Kd 1.0000 1.0000 1.0000
+    Ks 1.0000 1.0000 1.0000
+    ns 0.0000
+
+newmtl window
+    d 1.0000
+    illum 1
+    Ka 0.5000 0.5000 0.5000
+    Kd 1.0000 0.0000 0.0000
+    Ks 1.0000 1.0000 1.0000
+    ns 0.0000
diff --git a/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..88a5413
--- /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/video60</Front>
+            <Right>/dev/video61</Right>
+            <Rear>/dev/video62</Rear>
+            <Left>/dev/video63</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>1024</Width>
+            <Height>768</Height>
+        </OutputResolution>
+        <GroundMapping>
+            <Width>8.0</Width>
+            <Height>6.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>/vendor/etc/automotive/sv/sv_sample_car_model_config.xml</CarModelConfigFile>
+    <CarModelObjFile>/vendor/etc/automotive/sv/sample_car.obj</CarModelObjFile>
+    <Sv3dParams>
+        <OutputResolution>
+            <Width>1024</Width>
+            <Height>768</Height>
+        </OutputResolution>
+        <BowlParams>
+            <PlaneRadius>8.0</PlaneRadius>
+            <PlaneDivisions>50</PlaneDivisions>
+            <CurveHeight>6.0</CurveHeight>
+            <CurveDivisions>50</CurveDivisions>
+            <AngularDivisions>90</AngularDivisions>
+            <CurveCoefficient>3.0</CurveCoefficient>
+        </BowlParams>
+        <HighQualityDetails>
+            <Shadows>true</Shadows>
+            <Reflections>true</Reflections>
+        </HighQualityDetails>
+    </Sv3dParams>
+</SurroundViewConfig>
diff --git a/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..641bb43 100644
--- a/tests/CarDeveloperOptions/res/values-ar/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-ar/strings.xml
@@ -1799,8 +1799,8 @@
     <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_password_set_toast" msgid="601928982984489868">"تم تعيين كلمة المرور"</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>
     <string name="lockpassword_choose_your_password_header_for_face" msgid="8823110536502072216">"لاستخدام المصادقة بالوجه، اضبط كلمة المرور"</string>
@@ -4498,7 +4498,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> شهادة CA كحد أدنى</item>
       <item quantity="one">شهادة CA واحدة (<xliff:g id="COUNT_0">%d</xliff:g>) كحد أدنى</item>
     </plurals>
-    <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"يمكن للمشرف قفل الجهاز وإعادة تعيين كلمة المرور"</string>
+    <string name="enterprise_privacy_lock_device" msgid="1533125067038409945">"يمكن للمشرف قفل الجهاز وإعادة ضبط كلمة المرور"</string>
     <string name="enterprise_privacy_wipe_device" msgid="7555287990273929922">"يمكن للمشرف حذف جميع بيانات الجهاز"</string>
     <string name="enterprise_privacy_failed_password_wipe_device" msgid="4101502079202483156">"محاولات كلمة المرور الخاطئة قبل حذف جميع بيانات الجهاز"</string>
     <string name="enterprise_privacy_failed_password_wipe_work" msgid="2881646286634693392">"محاولات كلمة المرور الخاطئة قبل حذف بيانات الملف الشخصي للعمل"</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-be/strings.xml b/tests/CarDeveloperOptions/res/values-be/strings.xml
index 8c34666..2ae5de9 100644
--- a/tests/CarDeveloperOptions/res/values-be/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-be/strings.xml
@@ -1246,8 +1246,8 @@
     <string name="adaptive_sleep_summary_off" msgid="2891586225954973431">"Выключана"</string>
     <string name="adaptive_sleep_description" msgid="812673735459170009">"Не дазваляе экрану выключацца, калі на яго глядзяць"</string>
     <string name="adaptive_sleep_privacy" msgid="5706802215479902623">"Адаптыўны рэжым з дапамогай пярэдняй камеры вызначае, калі хто-небудзь глядзіць на экран. Функцыя працуе толькі на прыладзе: відарысы не захоўваюцца і не адпраўляюцца ў Google."</string>
-    <string name="night_display_title" msgid="1305002424893349814">"Начны рэжым"</string>
-    <string name="night_display_text" msgid="5330502493684652527">"У начным рэжыме экран будзе мець бурштынавае адценне. Так вам будзе зручней глядзець на экран пры цьмяным асвятленні, а таксама лягчэй заснуць."</string>
+    <string name="night_display_title" msgid="1305002424893349814">"Начная падсветка"</string>
+    <string name="night_display_text" msgid="5330502493684652527">"У рэжыме Начной падсветкі экран будзе мець бурштынавае адценне. Так вам будзе зручней глядзець на экран пры цьмяным асвятленні, а таксама лягчэй заснуць."</string>
     <string name="night_display_auto_mode_title" msgid="8493573087102481588">"Расклад"</string>
     <string name="night_display_auto_mode_never" msgid="2897444637217807088">"Ніколі"</string>
     <string name="night_display_auto_mode_custom" msgid="1400891076453963151">"Уключаецца ў вызначаны час"</string>
@@ -1270,7 +1270,7 @@
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Выключыць да вечара"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Уключыць да <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_activation_off_custom" msgid="4207238846687792731">"Выключыць да <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Начны рэжым не ўключаны"</string>
+    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Начная падсветка не ўключана"</string>
     <string name="screen_timeout" msgid="1700950247634525588">"Рэжым сну"</string>
     <string name="screen_timeout_title" msgid="150117777762864112">"Экран выключаецца"</string>
     <string name="screen_timeout_summary" msgid="8644192861778491060">"Пасля бяздзейнасці: <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g>"</string>
@@ -4028,9 +4028,9 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"Для выклікаў і апавяшчэнняў"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"Толькі вібрацыя"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"Для выклікаў і апавяшчэнняў"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Глядзець графік начнога рэжыму"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Задаць расклад Начной падсветкі"</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Аўтаматычна мяняць колер экрана ўвечары"</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"Начны рэжым уключаны"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"Начная падсветка ўключана"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Бурштынавы колер экрана"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"Адценні шэрага"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"Паказ толькі ў шэрым колеры"</string>
diff --git a/tests/CarDeveloperOptions/res/values-de/strings.xml b/tests/CarDeveloperOptions/res/values-de/strings.xml
index 022e8c8..214c3c5 100644
--- a/tests/CarDeveloperOptions/res/values-de/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-de/strings.xml
@@ -2904,7 +2904,7 @@
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"Entfernen"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"Telefonieren zulassen"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"Telefonieren &amp; SMS zulassen?"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"Telefonieren &amp; SMS zulassen"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"Nutzer löschen"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"Telefonieren zulassen?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Die Anrufliste wird für diesen Nutzer freigegeben."</string>
@@ -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-en-rAU/strings.xml b/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml
index 42ae028..ff3da11 100644
--- a/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rAU/strings.xml
@@ -1583,8 +1583,8 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
@@ -2064,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2202,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml b/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml
index 06ff9e5..cfbda4b 100644
--- a/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rCA/strings.xml
@@ -1583,8 +1583,8 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
@@ -2064,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2202,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml b/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml
index 42ae028..ff3da11 100644
--- a/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rGB/strings.xml
@@ -1583,8 +1583,8 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
@@ -2064,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2202,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</string>
diff --git a/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml b/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml
index 42ae028..ff3da11 100644
--- a/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-en-rIN/strings.xml
@@ -1583,8 +1583,8 @@
     <string name="reset_network_complete_toast" msgid="128225929536005495">"Network settings have been reset"</string>
     <string name="reset_esim_error_title" msgid="4728931209471875632">"Can’t delete SIMs"</string>
     <string name="reset_esim_error_msg" msgid="4716366079119742235">"Downloaded SIMs can’t be deleted due to an error.\n\nRestart your device and try again."</string>
-    <string name="master_clear_title" msgid="1560712943955904673">"Erase all data (factory reset)"</string>
-    <string name="master_clear_short_title" msgid="919098101581335101">"Erase all data (factory reset)"</string>
+    <string name="master_clear_title" msgid="1560712943955904673">"Delete all data (factory reset)"</string>
+    <string name="master_clear_short_title" msgid="919098101581335101">"Delete all data (factory reset)"</string>
     <string name="master_clear_desc" product="tablet" msgid="3432373610755760899">"This will erase all data from your tablet’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_desc" product="default" msgid="8765543541962866697">"This will erase all data from your phone’s "<b>"internal storage"</b>", including:\n\n"<li>"Your Google Account"</li>\n<li>"System and app data and settings"</li>\n<li>"Downloaded apps"</li></string>
     <string name="master_clear_accounts" product="default" msgid="3432884235445405376">\n\n"You are currently signed in to the following accounts:\n"</string>
@@ -2064,7 +2064,7 @@
     <string name="accessibility_global_gesture_preference_title" msgid="3842279082831426816">"Volume key shortcut"</string>
     <string name="accessibility_shortcut_service_title" msgid="3516052294376744060">"Shortcut service"</string>
     <string name="accessibility_shortcut_service_on_lock_screen_title" msgid="1279441617927949980">"Allow from lock screen"</string>
-    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for 3 seconds to start an accessibility feature."</string>
+    <string name="accessibility_shortcut_description" msgid="1427049334225166395">"When the shortcut is on, you can press both volume keys for three seconds to start an accessibility feature."</string>
     <string name="accessibility_toggle_high_text_contrast_preference_title" msgid="5652244684961877255">"High-contrast text"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_title" msgid="2466317284195934003">"Auto update screen magnification"</string>
     <string name="accessibility_toggle_screen_magnification_auto_update_preference_summary" msgid="6625473745911276917">"Update screen magnification on app transitions"</string>
@@ -2202,7 +2202,7 @@
       <item quantity="other"><xliff:g id="COUNT">%1$d</xliff:g> print jobs</item>
       <item quantity="one">1 print job</item>
     </plurals>
-    <string name="print_settings_title" msgid="2886445296786932763">"Printing services"</string>
+    <string name="print_settings_title" msgid="2886445296786932763">"Print services"</string>
     <string name="print_no_services_installed" msgid="3387777739528003794">"No services installed"</string>
     <string name="print_no_printers_found" msgid="5090925427392294881">"No printers found"</string>
     <string name="print_menu_item_settings" msgid="2654804159012579508">"Settings"</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..c67b9da 100644
--- a/tests/CarDeveloperOptions/res/values-es/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-es/strings.xml
@@ -1528,7 +1528,7 @@
     <string name="battery_level_title" msgid="5207775387973771646">"Nivel de batería"</string>
     <string name="apn_settings" msgid="8130776653826271664">"APNs"</string>
     <string name="apn_edit" msgid="4350571070853305357">"Editar punto de acceso"</string>
-    <string name="apn_not_set" msgid="5344235604466825691">"Sin establecer"</string>
+    <string name="apn_not_set" msgid="5344235604466825691">"Sin definir"</string>
     <string name="apn_name" msgid="8431432886706852226">"Nombre"</string>
     <string name="apn_apn" msgid="190519449579357696">"APN"</string>
     <string name="apn_http_proxy" msgid="8816906767987944465">"Proxy"</string>
@@ -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..c94af1e 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>
@@ -2904,7 +2904,7 @@
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"Eemalda"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"Lülita telefonikõned sisse"</string>
     <string name="user_enable_calling_sms" msgid="3450252891736718793">"Lülita telefonikõned ja SMS-id sisse"</string>
-    <string name="user_remove_user" msgid="3687544420125911166">"Kasutaja kustutamine"</string>
+    <string name="user_remove_user" msgid="3687544420125911166">"Kustuta kasutaja"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"Kas lülitada telefonikõned sisse?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"Selle kasutajaga jagatakse kõneajalugu."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"Kas lülitada telefonikõned ja SMS-id sisse?"</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-gu/strings.xml b/tests/CarDeveloperOptions/res/values-gu/strings.xml
index 49de15b..d72a8e6 100644
--- a/tests/CarDeveloperOptions/res/values-gu/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-gu/strings.xml
@@ -2903,11 +2903,11 @@
     <string name="user_exit_guest_confirm_message" msgid="6955182181145748919">"આ સત્રમાંની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"દૂર કરો"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"ફોન કૉલ ચાલુ કરો"</string>
-    <string name="user_enable_calling_sms" msgid="3450252891736718793">"ફોન કૉલ્સ અને SMS ચાલુ કરો"</string>
+    <string name="user_enable_calling_sms" msgid="3450252891736718793">"ફોન કૉલ અને SMS ચાલુ કરો"</string>
     <string name="user_remove_user" msgid="3687544420125911166">"વપરાશકર્તાને ડિલીટ કરો"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"ફોન કૉલ્સ ચાલુ કરીએ?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"કૉલ ઇતિહાસ આ વપરાશકર્તા સાથે શેર કરવામાં આવશે."</string>
-    <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ફોન કૉલ્સ અને SMS ચાલુ કરીએ?"</string>
+    <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"ફોન કૉલ અને SMS ચાલુ કરીએ?"</string>
     <string name="user_enable_calling_and_sms_confirm_message" msgid="3278802798876095734">"કૉલ અને SMS ઇતિહાસ આ વપરાશકર્તા સાથે શેર કરવામાં આવશે."</string>
     <string name="emergency_info_title" msgid="1522609271881425375">"ઇમર્જન્સીની માહિતી"</string>
     <string name="emergency_info_summary" msgid="7280464759837387342">"<xliff:g id="USER_NAME">%1$s</xliff:g> માટે માહિતી અને સંપર્કો"</string>
diff --git a/tests/CarDeveloperOptions/res/values-hi/strings.xml b/tests/CarDeveloperOptions/res/values-hi/strings.xml
index 180855c..e19e3fa 100644
--- a/tests/CarDeveloperOptions/res/values-hi/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-hi/strings.xml
@@ -2904,7 +2904,7 @@
     <string name="user_exit_guest_dialog_remove" msgid="1878866060881115716">"निकालें"</string>
     <string name="user_enable_calling" msgid="864760054792249503">"फ़ोन कॉल चालू करें"</string>
     <string name="user_enable_calling_sms" msgid="3450252891736718793">"फ़ोन कॉल और मैसेज (एसएमएस) चालू करें"</string>
-    <string name="user_remove_user" msgid="3687544420125911166">"उपयोगकर्ता को हटाना"</string>
+    <string name="user_remove_user" msgid="3687544420125911166">"उपयोगकर्ता को मिटाएं"</string>
     <string name="user_enable_calling_confirm_title" msgid="1141612415529158542">"फ़ोन कॉल चालू करें?"</string>
     <string name="user_enable_calling_confirm_message" msgid="2490126715153125970">"कॉल इतिहास इस उपयोगकर्ता के साथ शेयर किया जाएगा."</string>
     <string name="user_enable_calling_and_sms_confirm_title" msgid="4153856398523366976">"फ़ोन कॉल और मैसेज (एसएमएस) चालू करें?"</string>
@@ -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..60d43a3 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>
@@ -3306,10 +3306,10 @@
     <string name="hide_silent_icons_title" msgid="1070905516921542662">"Дыбыссыз хабарландыру күйінің белгішелерін жасыру"</string>
     <string name="hide_silent_icons_summary" msgid="2624346914488256888">"Күй жолағындағы дыбыссыз хабарландырулардың белгішелерін жасыру"</string>
     <string name="notification_badging_title" msgid="6311699476970264712">"Хабарландыру белгілеріне рұқсат беру"</string>
-    <string name="notification_bubbles_title" msgid="9196562435741861317">"Қалқымалы анықтамалар"</string>
+    <string name="notification_bubbles_title" msgid="9196562435741861317">"Қалқыма хабарлар"</string>
     <string name="notification_bubbles_summary" msgid="4624512775901949578">"Қалқымалы таңбашалар арқылы кез келген жерден қолданба мазмұнына жылдам кіру"</string>
     <string name="bubbles_feature_education" msgid="8979109826818881018">"Кейбір хабарландырулар және басқа мазмұндар экранға қалқымалы анықтамалар түрінде шығуы мүмкін. Қалқымалы анықтаманы ашу үшін оны түртіңіз. Жасыру үшін экранның төменгі жағына қарай сүйреңіз."</string>
-    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Қалқымалы анықтамалар"</string>
+    <string name="bubbles_app_toggle_title" msgid="6401217027603326439">"Қалқыма хабарлар"</string>
     <string name="bubbles_app_toggle_summary" msgid="7707611139796553855">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасына кейбір хабарландыруларды қалқымалы анықтама түрінде көрсетуге рұқсат береді."</string>
     <string name="bubbles_feature_disabled_dialog_title" msgid="3375452386012079293">"Қалқымалы анықтамаларды қосу"</string>
     <string name="bubbles_feature_disabled_dialog_text" msgid="326945485806386477">"Қалқымалы анықтамаларды қолданбада қосу үшін оларды алдымен құрылғыда қосу керек. Бұл бұрын қалқымалы анықтамалар қосылған қолданбалардың жұмысына әсер етеді."</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..9ba616e 100644
--- a/tests/CarDeveloperOptions/res/values-mn/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-mn/strings.xml
@@ -1424,9 +1424,9 @@
     <string name="usb_mtp_title" msgid="6893938968831995500">"Медиа төхөөрөмж (MTP)"</string>
     <string name="usb_mtp_summary" msgid="4427354560399094322">"Windows дээр медиа файлуудыг дамжуулах буюу Андройд Файл Дамжуулагчийг Mac дээр ашиглах боломж олгоно (www.android.com/filetransfer харна уу)"</string>
     <string name="usb_ptp_title" msgid="6629335976394685361">"Камер (PTP)"</string>
-    <string name="usb_ptp_summary" msgid="460425275251168189">"Танд камерын програм ашиглан зураг дамжуулах, компьютер дээрээс MTP-г дэмждэггүй ямар ч файлыг дамжуулах боломж олгоно"</string>
+    <string name="usb_ptp_summary" msgid="460425275251168189">"Танд камерын программ ашиглан зураг дамжуулах, компьютер дээрээс MTP-г дэмждэггүй ямар ч файлыг дамжуулах боломж олгоно"</string>
     <string name="usb_midi_title" msgid="8626512517313340943">"MIDI"</string>
-    <string name="usb_midi_summary" msgid="3607444815743771712">"MIDI-г идэвхжүүлсэн програмуудыг өөрийн компьютер дээрх MIDI програм хангамжийг USB дээр ажиллуулах."</string>
+    <string name="usb_midi_summary" msgid="3607444815743771712">"MIDI-г идэвхжүүлсэн программуудыг өөрийн компьютер дээрх MIDI программ хангамжийг USB дээр ажиллуулах."</string>
     <string name="storage_other_users" msgid="1055693465220962928">"Бусад хэрэглэгчид"</string>
     <string name="storage_internal_title" msgid="7969898703086593200">"Төхөөрөмжийн хадгалах сан"</string>
     <string name="storage_external_title" msgid="3308178326521953306">"Зөөврийн санах ой"</string>
@@ -1684,7 +1684,7 @@
     <string name="about_settings" product="default" msgid="6019547763377294261">"Утасны тухай"</string>
     <string name="about_settings" product="device" msgid="1770438316234693655">"Төхөөрөмжийн тухай"</string>
     <string name="about_settings" product="emulator" msgid="4497482494770487014">"Утасны мэдээллийн дэлгэц"</string>
-    <string name="about_settings_summary" msgid="4506081667462281647">"Хууль эрх зүйн мэдээлэл, статус, програмын хувилбарыг харах"</string>
+    <string name="about_settings_summary" msgid="4506081667462281647">"Хууль эрх зүйн мэдээлэл, статус, программын хувилбарыг харах"</string>
     <string name="legal_information" msgid="2374267257615182139">"Хууль эрх зүйн мэдээлэл"</string>
     <string name="contributors_title" msgid="6800028420806884340">"Хувь оруулагчид"</string>
     <string name="manual" msgid="5431859421432581357">"Гар ажиллагаатай"</string>
@@ -2536,7 +2536,7 @@
     <string name="advanced_security_title" msgid="286883005673855845">"Дэлгэрэнгүй"</string>
     <string name="credential_storage_type" msgid="2585337320206095255">"Хадгалах сангийн төрөл"</string>
     <string name="credential_storage_type_hardware" msgid="5054143224259023600">"Техник хангамжаар дэмжигдсэн"</string>
-    <string name="credential_storage_type_software" msgid="1335905150062717150">"Зөвхөн програм"</string>
+    <string name="credential_storage_type_software" msgid="1335905150062717150">"Зөвхөн программ"</string>
     <string name="credentials_settings_not_available" msgid="5490259681690183274">"Энэ хэрэглэгчид итгэмжлэл байхгүй байна"</string>
     <string name="credential_for_vpn_and_apps" msgid="2462642486949593841">"VPN, апп-д суулгасан"</string>
     <string name="credential_for_wifi" msgid="2903295786961726388">"Wi-Fi-д суулгасан"</string>
@@ -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>
@@ -4166,7 +4166,7 @@
     <string name="enterprise_privacy_settings" msgid="2777101678653072889">"Удирдсан төхөөрөмжийн мэдээлэл"</string>
     <string name="enterprise_privacy_settings_summary_generic" msgid="5557859169062703683">"Таны байгууллагын удирдсан тохиргооны өөрчлөлт"</string>
     <string name="enterprise_privacy_settings_summary_with_name" msgid="4884479123751308407">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-н удирдсан тохиргооны өөрчлөлт"</string>
-    <string name="enterprise_privacy_header" msgid="2680588186952421841">"Ажлынхаа өгөгдөлд хандах зөвшөөрлийг олгохын тулд таны байгууллага төхөөрөмжийн тохиргоог өөрчилж, програм хангамжийг суулгах шаардлагатай. \n\nДэлгэрэнгүй мэдээлэл авахын тулд байгууллагынхаа админтай холбогдоно уу."</string>
+    <string name="enterprise_privacy_header" msgid="2680588186952421841">"Ажлынхаа өгөгдөлд хандах зөвшөөрлийг олгохын тулд таны байгууллага төхөөрөмжийн тохиргоог өөрчилж, программ хангамжийг суулгах шаардлагатай. \n\nДэлгэрэнгүй мэдээлэл авахын тулд байгууллагынхаа админтай холбогдоно уу."</string>
     <string name="enterprise_privacy_exposure_category" msgid="4474576266043636753">"Таны байгууллага харах боломжтой мэдээллийн төрөл"</string>
     <string name="enterprise_privacy_exposure_changes_category" msgid="1877045221796512001">"Таны байгууллагын админы хийсэн өөрчлөлт"</string>
     <string name="enterprise_privacy_device_access_category" msgid="2967602674816237833">"Таны энэ төхөөрөмж дэх хандалт"</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-uk/strings.xml b/tests/CarDeveloperOptions/res/values-uk/strings.xml
index b39d1a4..c660174 100644
--- a/tests/CarDeveloperOptions/res/values-uk/strings.xml
+++ b/tests/CarDeveloperOptions/res/values-uk/strings.xml
@@ -1270,7 +1270,7 @@
     <string name="night_display_activation_off_twilight" msgid="6846727701281556110">"Вимкнути до заходу сонця"</string>
     <string name="night_display_activation_on_custom" msgid="4761140206778957611">"Увімкнути до <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="night_display_activation_off_custom" msgid="4207238846687792731">"Вимкнути до <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Нічний режим не ввімкнено"</string>
+    <string name="night_display_not_currently_on" msgid="1436588493764429281">"Нічний екран не ввімкнено"</string>
     <string name="screen_timeout" msgid="1700950247634525588">"Режим сну"</string>
     <string name="screen_timeout_title" msgid="150117777762864112">"Вимикати екран"</string>
     <string name="screen_timeout_summary" msgid="8644192861778491060">"Коли минає <xliff:g id="TIMEOUT_DESCRIPTION">%1$s</xliff:g> бездіяльності"</string>
@@ -4028,9 +4028,9 @@
     <string name="condition_device_muted_summary" msgid="3101055117680109021">"Для викликів і сповіщень"</string>
     <string name="condition_device_vibrate_title" msgid="5712659354868872338">"Лише вібрація"</string>
     <string name="condition_device_vibrate_summary" msgid="9073880731894828604">"Для викликів і сповіщень"</string>
-    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Налаштувати графік нічного режиму"</string>
+    <string name="night_display_suggestion_title" msgid="4222839610992282188">"Налаштувати графік функції \"Нічний екран\""</string>
     <string name="night_display_suggestion_summary" msgid="1754361016383576916">"Автоматично відтіняти екран щовечора"</string>
-    <string name="condition_night_display_title" msgid="9171491784857160135">"Нічне освітлення ввімкнено"</string>
+    <string name="condition_night_display_title" msgid="9171491784857160135">"Нічний екран увімкнено"</string>
     <string name="condition_night_display_summary" msgid="7885776986937527558">"Відтінок екрана змінено на бурштиновий"</string>
     <string name="condition_grayscale_title" msgid="1226351649203551299">"Відтінки сірого"</string>
     <string name="condition_grayscale_summary" msgid="749172886527349546">"Відображати все в сірому кольорі"</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/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java
index 489377e..186d188 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/TetherSettings.java
@@ -28,7 +28,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
 import android.os.Bundle;
@@ -373,25 +372,6 @@
         }
     }
 
-    public static boolean isProvisioningNeededButUnavailable(Context context) {
-        return (TetherUtil.isProvisioningNeeded(context)
-                && !isIntentAvailable(context));
-    }
-
-    private static boolean isIntentAvailable(Context context) {
-        String[] provisionApp = context.getResources().getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
-        if (provisionApp.length < 2) {
-            return false;
-        }
-        final PackageManager packageManager = context.getPackageManager();
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClassName(provisionApp[0], provisionApp[1]);
-
-        return (packageManager.queryIntentActivities(intent,
-                PackageManager.MATCH_DEFAULT_ONLY).size() > 0);
-    }
-
     private void startTethering(int choice) {
         if (choice == TETHERING_BLUETOOTH) {
             // Turn on Bluetooth first.
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java
index 53542b4..8150d9c 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherPreferenceController.java
@@ -39,7 +39,6 @@
 import androidx.preference.PreferenceScreen;
 
 import com.android.car.developeroptions.R;
-import com.android.car.developeroptions.TetherSettings;
 import com.android.car.developeroptions.core.PreferenceControllerMixin;
 import com.android.settingslib.TetherUtil;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -106,9 +105,6 @@
         if (mPreference != null && !mAdminDisallowedTetherConfig) {
             mPreference.setTitle(
                     com.android.settingslib.Utils.getTetheringLabel(mConnectivityManager));
-
-            // Grey out if provisioning is not available.
-            mPreference.setEnabled(!TetherSettings.isProvisioningNeededButUnavailable(mContext));
         }
     }
 
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java
index 3ffe0f6..5b699f1 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/network/TetherProvisioningActivity.java
@@ -19,16 +19,12 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
-import android.telephony.SubscriptionManager;
 import android.util.Log;
 
-import com.android.car.developeroptions.Utils;
-
 /**
  * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission
  * restrictions. Specifically, the provisioning apps require
@@ -41,6 +37,8 @@
     private static final String EXTRA_TETHER_TYPE = "TETHER_TYPE";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private ResultReceiver mResultReceiver;
+    public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME =
+            "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -51,10 +49,12 @@
 
         int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE,
                 ConnectivityManager.TETHERING_INVALID);
-        final int subId = SubscriptionManager.getDefaultDataSubscriptionId();
-        final Resources res = Utils.getResourcesForSubId(this, subId);
-        final String[] provisionApp = res.getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
+        String[] provisionApp = getIntent().getStringArrayExtra(
+                EXTRA_TETHER_UI_PROVISIONING_APP_NAME);
+        if (provisionApp == null || provisionApp.length != 2) {
+            Log.e(TAG, "Unexpected provision app configuration");
+            return;
+        }
 
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClassName(provisionApp[0], provisionApp[1]);
diff --git a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java
index dbedb4c..9b7d4b4 100644
--- a/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java
+++ b/tests/CarDeveloperOptions/src/com/android/car/developeroptions/wifi/tether/TetherService.java
@@ -32,7 +32,6 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.os.IBinder;
 import android.os.ResultReceiver;
@@ -44,10 +43,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.car.developeroptions.Utils;
-
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 public class TetherService extends Service {
     private static final String TAG = "TetherService";
@@ -55,6 +53,12 @@
 
     @VisibleForTesting
     public static final String EXTRA_RESULT = "EntitlementResult";
+    @VisibleForTesting
+    public static final String EXTRA_TETHER_PROVISIONING_RESPONSE =
+            "android.net.extra.TETHER_PROVISIONING_RESPONSE";
+    @VisibleForTesting
+    public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION =
+            "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION";
 
     // Activity results to match the activity provision protocol.
     // Default to something not ok.
@@ -69,6 +73,10 @@
 
     private int mCurrentTypeIndex;
     private boolean mInProvisionCheck;
+    /** Intent action received from the provisioning app when entitlement check completes. */
+    private String mExpectedProvisionResponseAction = null;
+    /** Intent action sent to the provisioning app to request an entitlement check. */
+    private String mProvisionAction;
     private TetherServiceWrapper mWrapper;
     private ArrayList<Integer> mCurrentTethers;
     private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks;
@@ -83,10 +91,6 @@
     public void onCreate() {
         super.onCreate();
         if (DEBUG) Log.d(TAG, "Creating TetherService");
-        String provisionResponse = getResourceForDefaultDataSubId().getString(
-                com.android.internal.R.string.config_mobile_hotspot_provision_response);
-        registerReceiver(mReceiver, new IntentFilter(provisionResponse),
-                android.Manifest.permission.CONNECTIVITY_INTERNAL, null);
         SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
         mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, ""));
         mCurrentTypeIndex = 0;
@@ -98,6 +102,24 @@
         mHotspotReceiver = new HotspotOffReceiver(this);
     }
 
+    // Registers the broadcast receiver for the specified response action, first unregistering
+    // the receiver if it was registered for a different response action.
+    private void maybeRegisterReceiver(final String responseAction) {
+        if (Objects.equals(responseAction, mExpectedProvisionResponseAction)) return;
+
+        if (mExpectedProvisionResponseAction != null) unregisterReceiver(mReceiver);
+
+        registerReceiver(mReceiver, new IntentFilter(responseAction),
+                android.Manifest.permission.TETHER_PRIVILEGED, null /* handler */);
+        mExpectedProvisionResponseAction = responseAction;
+        if (DEBUG) Log.d(TAG, "registerReceiver " + responseAction);
+    }
+
+    private int stopSelfAndStartNotSticky() {
+        stopSelf();
+        return START_NOT_STICKY;
+    }
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         if (intent.hasExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE)) {
@@ -111,9 +133,9 @@
                     callbacksForType.add(callback);
                 } else {
                     // Invalid tether type. Just ignore this request and report failure.
+                    Log.e(TAG, "Invalid tethering type " + type + ", stopping");
                     callback.send(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE, null);
-                    stopSelf();
-                    return START_NOT_STICKY;
+                    return stopSelfAndStartNotSticky();
                 }
             }
 
@@ -123,6 +145,19 @@
             }
         }
 
+        mProvisionAction = intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION);
+        if (mProvisionAction == null) {
+            Log.e(TAG, "null provisioning action, stop ");
+            return stopSelfAndStartNotSticky();
+        }
+
+        final String response = intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE);
+        if (response == null) {
+            Log.e(TAG, "null provisioning response, stop ");
+            return stopSelfAndStartNotSticky();
+        }
+        maybeRegisterReceiver(response);
+
         if (intent.hasExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE)) {
             if (!mInProvisionCheck) {
                 int type = intent.getIntExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE,
@@ -132,27 +167,17 @@
                 if (index >= 0) {
                     removeTypeAtIndex(index);
                 }
-                cancelAlarmIfNecessary();
             } else {
                 if (DEBUG) Log.d(TAG, "Don't cancel alarm during provisioning");
             }
         }
 
-        // Only set the alarm if we have one tether, meaning the one just added,
-        // to avoid setting it when it was already set previously for another
-        // type.
-        if (intent.getBooleanExtra(ConnectivityManager.EXTRA_SET_ALARM, false)
-                && mCurrentTethers.size() == 1) {
-            scheduleAlarm();
-        }
-
         if (intent.getBooleanExtra(ConnectivityManager.EXTRA_RUN_PROVISION, false)) {
             startProvisioning(mCurrentTypeIndex);
         } else if (!mInProvisionCheck) {
             // If we aren't running any provisioning, no reason to stay alive.
             if (DEBUG) Log.d(TAG, "Stopping self.  startid: " + startId);
-            stopSelf();
-            return START_NOT_STICKY;
+            return stopSelfAndStartNotSticky();
         }
         // We want to be started if we are killed accidently, so that we can be sure we finish
         // the check.
@@ -168,16 +193,15 @@
         SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE);
         prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit();
 
-        unregisterReceivers();
+        if (mExpectedProvisionResponseAction != null) {
+            unregisterReceiver(mReceiver);
+            mExpectedProvisionResponseAction = null;
+        }
+        mHotspotReceiver.unregister();
         if (DEBUG) Log.d(TAG, "Destroying TetherService");
         super.onDestroy();
     }
 
-    private void unregisterReceivers() {
-        unregisterReceiver(mReceiver);
-        mHotspotReceiver.unregister();
-    }
-
     private void removeTypeAtIndex(int index) {
         mCurrentTethers.remove(index);
         // If we are currently in the middle of a check, we may need to adjust the
@@ -246,22 +270,22 @@
     }
 
     private void startProvisioning(int index) {
-        if (index < mCurrentTethers.size()) {
-            Intent intent = getProvisionBroadcastIntent(index);
-            setEntitlementAppActive(index);
+        if (index >= mCurrentTethers.size()) return;
+        Intent intent = getProvisionBroadcastIntent(index);
+        setEntitlementAppActive(index);
 
-            if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction()
+        if (DEBUG) {
+            Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction()
                     + " type: " + mCurrentTethers.get(index));
-
-            sendBroadcast(intent);
-            mInProvisionCheck = true;
         }
+
+        sendBroadcast(intent);
+        mInProvisionCheck = true;
     }
 
     private Intent getProvisionBroadcastIntent(int index) {
-        String provisionAction = getResourceForDefaultDataSubId().getString(
-                com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui);
-        Intent intent = new Intent(provisionAction);
+        if (mProvisionAction == null) Log.wtf(TAG, "null provisioning action");
+        Intent intent = new Intent(mProvisionAction);
         int type = mCurrentTethers.get(index);
         intent.putExtra(TETHER_CHOICE, type);
         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -295,9 +319,7 @@
 
         PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
         AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
-        int period = getResourceForDefaultDataSubId().getInteger(
-                com.android.internal.R.integer.config_mobile_hotspot_provision_check_period);
-        long periodMs = period * MS_PER_HOUR;
+        long periodMs = 24 * MS_PER_HOUR;
         long firstTime = SystemClock.elapsedRealtime() + periodMs;
         if (DEBUG) Log.d(TAG, "Scheduling alarm at interval " + periodMs);
         alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, periodMs,
@@ -348,40 +370,48 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Log.d(TAG, "Got provision result " + intent);
-            String provisionResponse = getResourceForDefaultDataSubId().getString(
-                    com.android.internal.R.string.config_mobile_hotspot_provision_response);
+            if (!intent.getAction().equals(mExpectedProvisionResponseAction)) {
+                Log.e(TAG, "Received provisioning response for unexpected action="
+                        + intent.getAction() + ", expected=" + mExpectedProvisionResponseAction);
+                return;
+            }
 
-            if (provisionResponse.equals(intent.getAction())) {
-                if (!mInProvisionCheck) {
-                    Log.e(TAG, "Unexpected provision response " + intent);
-                    return;
-                }
-                int checkType = mCurrentTethers.get(mCurrentTypeIndex);
-                mInProvisionCheck = false;
-                int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT);
-                if (result != RESULT_OK) {
-                    switch (checkType) {
-                        case ConnectivityManager.TETHERING_WIFI:
-                            disableWifiTethering();
-                            break;
-                        case ConnectivityManager.TETHERING_BLUETOOTH:
-                            disableBtTethering();
-                            break;
-                        case ConnectivityManager.TETHERING_USB:
-                            disableUsbTethering();
-                            break;
-                    }
-                }
-                fireCallbacksForType(checkType, result);
+            if (!mInProvisionCheck) {
+                Log.e(TAG, "Unexpected provisioning response when not in provisioning check"
+                        + intent);
+                return;
+            }
 
-                if (++mCurrentTypeIndex >= mCurrentTethers.size()) {
-                    // We are done with all checks, time to die.
-                    stopSelf();
-                } else {
-                    // Start the next check in our list.
-                    startProvisioning(mCurrentTypeIndex);
+
+            if (!mInProvisionCheck) {
+                Log.e(TAG, "Unexpected provision response " + intent);
+                return;
+            }
+            int checkType = mCurrentTethers.get(mCurrentTypeIndex);
+            mInProvisionCheck = false;
+            int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT);
+            if (result != RESULT_OK) {
+                switch (checkType) {
+                    case ConnectivityManager.TETHERING_WIFI:
+                        disableWifiTethering();
+                        break;
+                    case ConnectivityManager.TETHERING_BLUETOOTH:
+                        disableBtTethering();
+                        break;
+                    case ConnectivityManager.TETHERING_USB:
+                        disableUsbTethering();
+                        break;
                 }
             }
+            fireCallbacksForType(checkType, result);
+
+            if (++mCurrentTypeIndex >= mCurrentTethers.size()) {
+                // We are done with all checks, time to die.
+                stopSelf();
+            } else {
+                // Start the next check in our list.
+                startProvisioning(mCurrentTypeIndex);
+            }
         }
     };
 
@@ -399,8 +429,7 @@
 
     /**
      * A static helper class used for tests. UsageStatsManager cannot be mocked out because
-     * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot
-     * be mocked. This class can be mocked out instead.
+     * it's marked final. This class can be mocked out instead.
      */
     @VisibleForTesting
     public static class TetherServiceWrapper {
@@ -419,10 +448,4 @@
             return SubscriptionManager.getDefaultDataSubscriptionId();
         }
     }
-
-    @VisibleForTesting
-    Resources getResourceForDefaultDataSubId() {
-        final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId();
-        return Utils.getResourcesForSubId(this, subId);
-    }
 }
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/notification_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
index 43be213..4610f4c 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/notification_fragment.xml
@@ -199,6 +199,7 @@
                 android:background="#ffa9a8"
                 android:foreground="?android:attr/selectableItemBackground"
                 android:text="Car Emergency"
+                android:enabled="false"
                 android:textSize="30sp"/>
 
             <Button
@@ -209,6 +210,7 @@
                 android:background="#ffa9a8"
                 android:foreground="?android:attr/selectableItemBackground"
                 android:text="Car Warning"
+                android:enabled="false"
                 android:textSize="30sp"/>
 
             <Button
@@ -217,6 +219,7 @@
                 android:layout_height="wrap_content"
                 android:layout_margin="10dp"
                 android:text="Car Information"
+                android:enabled="false"
                 android:textSize="30sp"/>
         </LinearLayout>
     </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_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java b/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
index 78fd6f7..7890d5a 100644
--- a/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/CarUxRestrictionsManagerServiceTest.java
@@ -388,7 +388,8 @@
         int displayIdForPhysicalPort1 = 0;
         int displayIdForPhysicalPort2 = 1;
         int virtualDisplayId = 2;
-        int physicalPortForFirstDisplay = 0;
+        int physicalDisplayIdForVirtualDisplayId2 = displayIdForPhysicalPort2;
+        int physicalPortForFirstDisplay = 10;
         int physicalPortForSecondDisplay = 11;
         when(mSpyContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
         mockDisplay(mDisplayManager, mDisplay0, displayIdForPhysicalPort1,
@@ -418,7 +419,7 @@
         mService.init();
         // A CarActivityView would report this itself, but we fake the report here
         mService.reportVirtualDisplayToPhysicalDisplay(mRemoteCallback, virtualDisplayId,
-                physicalPortForSecondDisplay);
+                physicalDisplayIdForVirtualDisplayId2);
         mService.handleDrivingStateEventLocked(
                 new CarDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_MOVING,
                         SystemClock.elapsedRealtime()));
diff --git a/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
index 29a1946..cbd33b0 100644
--- a/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/userlib/UserHalHelperTest.java
@@ -207,6 +207,20 @@
     }
 
     @Test
+    public void testIsDisabled() {
+        assertThat(UserHalHelper.isDisabled(UserFlags.DISABLED)).isTrue();
+        assertThat(UserHalHelper.isDisabled(UserFlags.DISABLED | 666)).isTrue();
+        assertThat(UserHalHelper.isDisabled(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
+    public void testIsProfile() {
+        assertThat(UserHalHelper.isProfile(UserFlags.PROFILE)).isTrue();
+        assertThat(UserHalHelper.isProfile(UserFlags.PROFILE | 666)).isTrue();
+        assertThat(UserHalHelper.isProfile(UserFlags.GUEST)).isFalse();
+    }
+
+    @Test
     public void testToUserInfoFlags() {
         assertThat(UserHalHelper.toUserInfoFlags(UserFlags.NONE)).isEqualTo(0);
         assertThat(UserHalHelper.toUserInfoFlags(UserFlags.EPHEMERAL))
@@ -1191,6 +1205,7 @@
     }
 
     @Test
+    @ExpectWtf
     public void testNewUsersInfo_noCurrentUser() {
         UserInfo user100 = new UserInfoBuilder(100).setFlags(UserInfo.FLAG_ADMIN).build();
         UserInfo user200 = new UserInfoBuilder(200).build();
diff --git a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
new file mode 100644
index 0000000..fe45782
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
@@ -0,0 +1,353 @@
+/*
+ * 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.android.car.media;
+
+import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE;
+import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.car.Car;
+import android.car.media.ICarMediaSourceListener;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.AndroidMockitoHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.UserManager;
+
+import com.android.car.CarMediaService;
+import com.android.car.R;
+import com.android.car.user.CarUserService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CarMediaServiceTest extends AbstractExtendedMockitoTestCase {
+
+    private static final String MEDIA_PACKAGE = "test.package";
+    private static final String MEDIA_PACKAGE2 = "test.package2";
+    private static final String MEDIA_CLASS = "test_class";
+    private static final String MEDIA_CLASS2 = "test_class2";
+
+    private static final int TEST_USER_ID = 100;
+
+    private static final ComponentName MEDIA_COMPONENT =
+            new ComponentName(MEDIA_PACKAGE, MEDIA_CLASS);
+    private static final ComponentName MEDIA_COMPONENT2 =
+            new ComponentName(MEDIA_PACKAGE2, MEDIA_CLASS2);
+
+    @Mock private Context mContext;
+    @Mock private Resources mResources;
+    @Mock private CarUserService mUserService;
+    @Mock private UserManager mUserManager;
+    @Mock private PackageManager mPackageManager;
+    @Mock private MediaSessionManager mMediaSessionManager;
+
+    private CarMediaService mCarMediaService;
+
+    @Override
+    protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
+        builder.spyStatic(ActivityManager.class);
+    }
+
+    @Before
+    public void setUp() {
+        when(mContext.checkCallingOrSelfPermission(anyString()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+        doReturn(mResources).when(mContext).getResources();
+        doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
+        UserInfo userInfo = new UserInfo(TEST_USER_ID, "test_user", UserInfo.FLAG_PRIMARY);
+        AndroidMockitoHelper.mockAmGetCurrentUser(TEST_USER_ID);
+        AndroidMockitoHelper.mockUmGetUserInfo(mUserManager, userInfo);
+        doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class);
+
+        mCarMediaService = new CarMediaService(mContext, mUserService);
+    }
+
+    @Test
+    public void testSetMediaSource_ModePlaybackIndependent() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isNotEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testSetMediaSource_ModeBrowseIndependent() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isNotEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testSetMediaSource_ModePlaybackAndBrowseIndependent() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testSetMediaSource_Dependent() {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_BROWSE);
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT2);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testMediaSourceListener_Independent() throws Exception {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+        ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
+        ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerBrowse, never()).onMediaSourceChanged(any());
+    }
+
+    @Test
+    public void testMediaSourceListener_IndependentBrowse() throws Exception {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+        ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
+        ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+
+        verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerPlayback, never()).onMediaSourceChanged(any());
+    }
+
+    @Test
+    public void testMediaSourceListener_Dependent() throws Exception {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+        ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
+        ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
+
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
+
+        verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
+        verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testMediaSourceListener_Unregister() throws Exception {
+        ICarMediaSourceListener listener = mockMediaSourceListener();
+
+        mCarMediaService.registerMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.unregisterMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK);
+        mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
+
+        verify(listener, never()).onMediaSourceChanged(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testDefaultMediaSource() {
+        initializeMockPackageManager(MEDIA_CLASS);
+        mockUserUnlocked(true);
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testUnresolvedMediaPackage() {
+        initializeMockPackageManager();
+
+        assertThat(mCarMediaService.isMediaService(MEDIA_COMPONENT)).isFalse();
+    }
+
+    // Tests that PlaybackState changing to STATE_PLAYING will result the media source changing
+    @Test
+    public void testActiveSessionListener_StatePlayingChangesSource() {
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testActiveSessionListener_IndependentBrowseUnchanged() {
+        mCarMediaService.setIndependentPlaybackConfig(true);
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT);
+    }
+
+    @Test
+    public void testActiveSessionListener_DependentBrowseChanged() {
+        mCarMediaService.setIndependentPlaybackConfig(false);
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT2);
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
+                .isEqualTo(MEDIA_COMPONENT2);
+    }
+
+    @Test
+    public void testActiveSessionListener_StatePaused() {
+        initializeMockPackageManager(MEDIA_CLASS, MEDIA_CLASS2);
+        mockUserUnlocked(true);
+        mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PAUSED));
+
+        mCarMediaService.init();
+
+        assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
+                .isEqualTo(MEDIA_COMPONENT);
+    }
+
+    private void mockUserUnlocked(boolean unlocked) {
+        when(mUserManager.isUserUnlocked(anyInt())).thenReturn(unlocked);
+    }
+
+    private ICarMediaSourceListener mockMediaSourceListener() {
+        ICarMediaSourceListener listener = mock(ICarMediaSourceListener.class);
+        when(listener.asBinder()).thenReturn(mock(IBinder.class));
+        return listener;
+    }
+
+    // This method invokes a playback state changed callback on a mock MediaController
+    private void mockPlaybackStateChange(PlaybackState newState) {
+        List<MediaController> controllers = new ArrayList<>();
+        MediaController mockController = mock(MediaController.class);
+        when(mockController.getPackageName()).thenReturn(MEDIA_PACKAGE2);
+        when(mockController.getSessionToken()).thenReturn(mock(MediaSession.Token.class));
+        Bundle sessionExtras = new Bundle();
+        sessionExtras.putString(Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION, MEDIA_CLASS2);
+        when(mockController.getExtras()).thenReturn(sessionExtras);
+
+        doAnswer(invocation -> {
+            MediaController.Callback callback = invocation.getArgument(0);
+            callback.onPlaybackStateChanged(newState);
+            return null;
+        }).when(mockController).registerCallback(notNull());
+        controllers.add(mockController);
+
+        doAnswer(invocation -> {
+            MediaSessionManager.OnActiveSessionsChangedListener callback =
+                    invocation.getArgument(0);
+            callback.onActiveSessionsChanged(controllers);
+            return null;
+        }).when(mMediaSessionManager).addOnActiveSessionsChangedListener(any(
+                MediaSessionManager.OnActiveSessionsChangedListener.class), any(), anyInt(), any());
+    }
+
+    // This method sets up PackageManager queries to return mocked media components if specified
+    private void initializeMockPackageManager(String... classesToResolve) {
+        when(mContext.getString(R.string.config_defaultMediaSource))
+                .thenReturn(MEDIA_COMPONENT.flattenToShortString());
+        List<ResolveInfo> packageList = new ArrayList();
+        for (String className : classesToResolve) {
+            ResolveInfo info = new ResolveInfo();
+            ServiceInfo serviceInfo = new ServiceInfo();
+            serviceInfo.name = className;
+            info.serviceInfo = serviceInfo;
+            packageList.add(info);
+        }
+        when(mPackageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt()))
+                .thenReturn(packageList);
+    }
+
+    private PlaybackState createPlaybackState(@PlaybackState.State int state) {
+        return new PlaybackState.Builder().setState(state, 0, 0).build();
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
index 3d38ac4..8a024aa 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java
@@ -47,10 +47,12 @@
 import android.car.user.UserIdentificationAssociationResponse;
 import android.car.user.UserRemovalResult;
 import android.car.user.UserSwitchResult;
+import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.pm.UserInfo.UserInfoFlag;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.provider.Settings;
 
 import com.android.internal.infra.AndroidFuture;
 
@@ -66,6 +68,8 @@
     private UserManager mUserManager;
     @Mock
     private ICarUserService mService;
+    @Mock
+    private Context mMockContext;
 
     private CarUserManager mMgr;
 
@@ -77,6 +81,7 @@
     @Before
     public void setFixtures() {
         mMgr = new CarUserManager(mCar, mService, mUserManager);
+        when(mCar.getContext()).thenReturn(mMockContext);
     }
 
     @Test
@@ -176,6 +181,19 @@
     }
 
     @Test
+    public void testSwitchUser_noUserSwitchability() throws Exception {
+        when(mUserManager.getUserSwitchability())
+                .thenReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
+
+        AndroidFuture<UserSwitchResult> future = mMgr.switchUser(11);
+
+        assertThat(future).isNotNull();
+        UserSwitchResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_NOT_SWITCHABLE);
+        assertThat(result.getErrorMessage()).isNull();
+    }
+
+    @Test
     public void testSwitchUser_remoteException() throws Exception {
         expectServiceSwitchUserFails(11);
         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
@@ -225,7 +243,7 @@
     }
 
     @Test
-    public void testCreateUser_success() throws Exception {
+    public void testCreateUser_withType_success() throws Exception {
         expectServiceCreateUserSucceeds("dude", "sweet", 42, UserCreationResult.STATUS_SUCCESSFUL,
                 108);
 
@@ -246,7 +264,7 @@
     }
 
     @Test
-    public void testCreateUser_remoteException() throws Exception {
+    public void testCreateUser_withType_remoteException() throws Exception {
         expectServiceCreateUserFails("dude", "sweet", 42);
         mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
 
@@ -261,6 +279,79 @@
     }
 
     @Test
+    public void testCreateUser_success() throws Exception {
+        expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42,
+                UserCreationResult.STATUS_SUCCESSFUL, 108);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.isSuccess()).isTrue();
+        assertThat(result.getErrorMessage()).isNull();
+
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(108);
+        assertThat(newUser.name).isEqualTo("dude");
+        assertThat(newUser.userType).isEqualTo(UserManager.USER_TYPE_FULL_SECONDARY);
+        assertThat(newUser.flags).isEqualTo(42);
+    }
+
+    @Test
+    public void testCreateUser_remoteException() throws Exception {
+        expectServiceCreateUserFails("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42);
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createUser("dude", 42);
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getUser()).isNull();
+    }
+
+    @Test
+    public void testCreateGuest_success() throws Exception {
+        expectServiceCreateUserSucceeds("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0,
+                UserCreationResult.STATUS_SUCCESSFUL, 108);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL);
+        assertThat(result.isSuccess()).isTrue();
+        assertThat(result.getErrorMessage()).isNull();
+
+        UserInfo newUser = result.getUser();
+        assertThat(newUser).isNotNull();
+        assertThat(newUser.id).isEqualTo(108);
+        assertThat(newUser.name).isEqualTo("dudeGuest");
+        assertThat(newUser.userType).isEqualTo(UserManager.USER_TYPE_FULL_GUEST);
+        assertThat(newUser.flags).isEqualTo(0);
+        assertThat(getSettingsString(Settings.Secure.SKIP_FIRST_USE_HINTS)).isEqualTo("1");
+    }
+
+    @Test
+    public void testCreateGuest_remoteException() throws Exception {
+        expectServiceCreateUserFails("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0);
+        mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar);
+
+        AndroidFuture<UserCreationResult> future = mMgr.createGuest("dudeGuest");
+
+        assertThat(future).isNotNull();
+        UserCreationResult result = getResult(future);
+        assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE);
+        assertThat(result.isSuccess()).isFalse();
+        assertThat(result.getErrorMessage()).isNull();
+        assertThat(result.getUser()).isNull();
+    }
+
+    @Test
     public void testGetUserIdentificationAssociation_nullTypes() throws Exception {
         assertThrows(IllegalArgumentException.class,
                 () -> mMgr.getUserIdentificationAssociation(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..b339c9a 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
@@ -249,7 +249,7 @@
     @Test
     public void testOnUserLifecycleEvent_legacyUserSwitch_halCalled() throws Exception {
         // Arrange
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
 
         // Act
         sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
@@ -261,7 +261,7 @@
     @Test
     public void testOnUserLifecycleEvent_legacyUserSwitch_halnotSupported() throws Exception {
         // Arrange
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
         mockUserHalSupported(false);
 
         // Act
@@ -275,7 +275,7 @@
     public void testOnUserLifecycleEvent_notifyListener() throws Exception {
         // Arrange
         mCarUserService.addUserLifecycleListener(mUserLifecycleListener);
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
 
         // Act
         sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
@@ -293,7 +293,7 @@
         doThrow(new RuntimeException("Failed onEvent invocation")).when(
                 failureListener).onEvent(any(UserLifecycleEvent.class));
         mCarUserService.addUserLifecycleListener(failureListener);
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
 
         // Adding the non-failure listener later.
         mCarUserService.addUserLifecycleListener(mUserLifecycleListener);
@@ -339,7 +339,7 @@
     @Test
     public void testLastActiveUserUpdatedOnUserSwitch_nonHeadlessSystemUser() throws Exception {
         mockIsHeadlessSystemUser(mRegularUser.id, false);
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
 
         sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
 
@@ -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
@@ -712,7 +712,7 @@
     @Test
     public void testRemoveUser_lastAdminUser() throws Exception {
         mockCurrentUser(mRegularUser);
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
 
         UserRemovalResult result = mCarUserService.removeUser(mAdminUser.id);
 
@@ -722,29 +722,41 @@
 
     @Test
     public void testRemoveUser_notLastAdminUser_success() throws Exception {
-        // Give admin rights to regular user.
+        List<UserInfo> existingUsers =
+                new ArrayList<UserInfo>(Arrays.asList(mAdminUser, mGuestUser, mRegularUser));
         UserInfo currentUser = mRegularUser;
+        // Give admin rights to current user.
         currentUser.flags = currentUser.flags | FLAG_ADMIN;
-        mockExistingUsersAndCurrentUser(currentUser);
-        int removeUserId = mAdminUser.id;
-        when(mMockedUserManager.removeUser(removeUserId)).thenReturn(true);
+        mockExistingUsersAndCurrentUser(existingUsers, currentUser);
 
-        UserRemovalResult result = mCarUserService.removeUser(removeUserId);
+        UserInfo removeUser = mAdminUser;
+        doAnswer((invocation) -> {
+            existingUsers.remove(removeUser);
+            return true;
+        }).when(mMockedUserManager).removeUser(eq(removeUser.id));
+
+        UserRemovalResult result = mCarUserService.removeUser(removeUser.id);
 
         assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
-        assertHalRemove(currentUser.id, removeUserId);
+        assertHalRemove(currentUser, removeUser, existingUsers);
     }
 
     @Test
     public void testRemoveUser_success() throws Exception {
-        mockExistingUsersAndCurrentUser(mAdminUser);
-        int removeUserId = mRegularUser.id;
-        when(mMockedUserManager.removeUser(removeUserId)).thenReturn(true);
+        List<UserInfo> existingUsers =
+                new ArrayList<UserInfo>(Arrays.asList(mAdminUser, mGuestUser, mRegularUser));
+        UserInfo currentUser = mAdminUser;
+        mockExistingUsersAndCurrentUser(existingUsers, currentUser);
+        UserInfo removeUser = mRegularUser;
+        doAnswer((invocation) -> {
+            existingUsers.remove(removeUser);
+            return true;
+        }).when(mMockedUserManager).removeUser(eq(removeUser.id));
 
-        UserRemovalResult result = mCarUserService.removeUser(removeUserId);
+        UserRemovalResult result = mCarUserService.removeUser(removeUser.id);
 
         assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL);
-        assertHalRemove(mAdminUser.id, removeUserId);
+        assertHalRemove(currentUser, removeUser, existingUsers);
     }
 
     @Test
@@ -792,7 +804,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
@@ -1109,7 +1121,7 @@
 
     @Test
     public void testLegacyUserSwitch_ok() throws Exception {
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
 
         sendUserSwitchingEvent(mAdminUser.id, mRegularUser.id);
 
@@ -1757,13 +1769,19 @@
      */
     private void mockExistingUsersAndCurrentUser(@NonNull UserInfo user)
             throws Exception {
-        mockExistingUsers();
+        mockExistingUsers(mExistingUsers);
         mockCurrentUser(user);
     }
 
-    private void mockExistingUsers() {
-        mockUmGetUsers(mMockedUserManager, mExistingUsers);
-        for (UserInfo user : mExistingUsers) {
+    private void mockExistingUsersAndCurrentUser(@NonNull List<UserInfo> existingUsers,
+            @NonNull UserInfo currentUser) throws Exception {
+        mockExistingUsers(existingUsers);
+        mockCurrentUser(currentUser);
+    }
+
+    private void mockExistingUsers(@NonNull List<UserInfo> existingUsers) {
+        mockUmGetUsers(mMockedUserManager, existingUsers);
+        for (UserInfo user : existingUsers) {
             AndroidMockitoHelper.mockUmGetUserInfo(mMockedUserManager, user);
         }
     }
@@ -1966,7 +1984,6 @@
         when(mUserHal.isUserAssociationSupported()).thenReturn(result);
     }
 
-
     /**
      * Asserts a {@link UsersInfo} that was created based on {@link #mockCurrentUsers(UserInfo)}.
      */
@@ -2098,12 +2115,18 @@
         verify(mUserHal, never()).createUser(any(), eq(mAsyncCallTimeoutMs), any());
     }
 
-    private void assertHalRemove(int currentId, int removeUserId) {
+    private void assertHalRemove(@NonNull UserInfo currentUser, @NonNull UserInfo removeUser,
+            @NonNull List<UserInfo> existingUsers) {
         ArgumentCaptor<RemoveUserRequest> request =
                 ArgumentCaptor.forClass(RemoveUserRequest.class);
         verify(mUserHal).removeUser(request.capture());
-        assertThat(request.getValue().removedUserInfo.userId).isEqualTo(removeUserId);
-        assertThat(request.getValue().usersInfo.currentUser.userId).isEqualTo(currentId);
+        assertThat(request.getValue().removedUserInfo.userId).isEqualTo(removeUser.id);
+        assertThat(request.getValue().usersInfo.currentUser.userId).isEqualTo(currentUser.id);
+        UsersInfo receivedExistingUsers = request.getValue().usersInfo;
+        assertThat(receivedExistingUsers.numberUsers).isEqualTo(existingUsers.size());
+        for (int i = 0; i < receivedExistingUsers.numberUsers; i++) {
+            assertSameUser(receivedExistingUsers.existingUsers.get(i), existingUsers.get(i));
+        }
     }
 
     @NonNull
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();
     }
 }
diff --git a/user/car-user-lib/src/android/car/userlib/UserHalHelper.java b/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
index 67a83c3..d2beddb 100644
--- a/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
+++ b/user/car-user-lib/src/android/car/userlib/UserHalHelper.java
@@ -121,7 +121,6 @@
      */
     public static int convertFlags(@NonNull UserInfo user) {
         checkArgument(user != null, "user cannot be null");
-        checkArgument(user != null, "user cannot be null");
 
         int flags = UserFlags.NONE;
         if (user.id == UserHandle.USER_SYSTEM) {
@@ -136,6 +135,12 @@
         if (user.isEphemeral()) {
             flags |= UserFlags.EPHEMERAL;
         }
+        if (!user.isEnabled()) {
+            flags |= UserFlags.DISABLED;
+        }
+        if (user.isProfile()) {
+            flags |= UserFlags.PROFILE;
+        }
 
         return flags;
     }
@@ -179,6 +184,20 @@
     }
 
     /**
+     * Checks if a HAL flag contains {@link UserFlags#DISABLED}.
+     */
+    public static boolean isDisabled(int flags) {
+        return (flags & UserFlags.DISABLED) != 0;
+    }
+
+    /**
+     * Checks if a HAL flag contains {@link UserFlags#PROFILE}.
+     */
+    public static boolean isProfile(int flags) {
+        return (flags & UserFlags.PROFILE) != 0;
+    }
+
+    /**
      * Converts HAL flags to Android's.
      */
     @UserInfoFlag
@@ -578,7 +597,8 @@
     public static UsersInfo newUsersInfo(@NonNull UserManager um, @UserIdInt int userId) {
         Preconditions.checkArgument(um != null, "UserManager cannot be null");
 
-        List<UserInfo> users = um.getUsers(/*excludeDying= */ true);
+        List<UserInfo> users = um.getUsers(/* excludePartial= */ false, /* excludeDying= */ false,
+                /* excludePreCreated= */ true);
 
         if (users == null || users.isEmpty()) {
             Log.w(TAG, "newUsersInfo(): no users");
@@ -605,8 +625,8 @@
         if (currentUser != null) {
             usersInfo.currentUser.flags = convertFlags(currentUser);
         } else {
-            Log.w(TAG, "newUsersInfo(): could not get flags for current user ("
-                    + usersInfo.currentUser.userId + ")");
+            // This should not happen.
+            Log.wtf(TAG, "Current user is not part of existing users. usersInfo: " + usersInfo);
         }
 
         return usersInfo;